diff --git a/airbyte-integrations/connectors/source-harvest/.coveragerc b/airbyte-integrations/connectors/source-harvest/.coveragerc deleted file mode 100644 index 7abb63521095..000000000000 --- a/airbyte-integrations/connectors/source-harvest/.coveragerc +++ /dev/null @@ -1,3 +0,0 @@ -[run] -omit = - source_harvest/run.py diff --git a/airbyte-integrations/connectors/source-harvest/README.md b/airbyte-integrations/connectors/source-harvest/README.md index 6c989b655899..ef9dadce0c9b 100644 --- a/airbyte-integrations/connectors/source-harvest/README.md +++ b/airbyte-integrations/connectors/source-harvest/README.md @@ -1,49 +1,22 @@ # Harvest source connector -This is the repository for the Harvest source connector, written in Python. -For information about how to use this connector within Airbyte, see [the documentation](https://docs.airbyte.com/integrations/sources/harvest). +This directory contains the manifest-only connector for `source-harvest`. +This _manifest-only_ connector is not a Python package on its own, as it runs inside of the base `source-declarative-manifest` image. -## Local development - -### Prerequisites - -- Python (~=3.9) -- Poetry (~=1.7) - installation instructions [here](https://python-poetry.org/docs/#installation) - -### Installing the connector - -From this connector directory, run: - -```bash -poetry install --with dev -``` - -### Create credentials +For information about how to configure and use this connector within Airbyte, see [the connector's full documentation](https://docs.airbyte.com/integrations/sources/harvest). -**If you are a community contributor**, follow the instructions in the [documentation](https://docs.airbyte.com/integrations/sources/harvest) -to generate the necessary credentials. Then create a file `secrets/config.json` conforming to the `source_harvest/spec.yaml` file. -Note that any directory named `secrets` is gitignored across the entire Airbyte repo, so there is no danger of accidentally checking in sensitive information. -See `sample_files/sample_config.json` for a sample config file. - -### Locally running the connector - -``` -poetry run source-harvest spec -poetry run source-harvest check --config secrets/config.json -poetry run source-harvest discover --config secrets/config.json -poetry run source-harvest read --config secrets/config.json --catalog integration_tests/configured_catalog.json -``` +## Local development -### Running unit tests +We recommend using the Connector Builder to edit this connector. +Using either Airbyte Cloud or your local Airbyte OSS instance, navigate to the **Builder** tab and select **Import a YAML**. +Then select the connector's `manifest.yaml` file to load the connector into the Builder. You're now ready to make changes to the connector! -To run unit tests locally, from the connector directory run: - -``` -poetry run pytest unit_tests -``` +If you prefer to develop locally, you can follow the instructions below. ### Building the docker image +You can build any manifest-only connector with `airbyte-ci`: + 1. Install [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md) 2. Run the following command to build the docker image: @@ -53,18 +26,24 @@ airbyte-ci connectors --name=source-harvest build An image will be available on your host with the tag `airbyte/source-harvest:dev`. +### Creating credentials + +**If you are a community contributor**, follow the instructions in the [documentation](https://docs.airbyte.com/integrations/sources/harvest) +to generate the necessary credentials. Then create a file `secrets/config.json` conforming to the `spec` object in the connector's `manifest.yaml` file. +Note that any directory named `secrets` is gitignored across the entire Airbyte repo, so there is no danger of accidentally checking in sensitive information. + ### Running as a docker container -Then run any of the connector commands as follows: +Then run any of the standard source connector commands: -``` +```bash docker run --rm airbyte/source-harvest:dev spec docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-harvest:dev check --config /secrets/config.json docker run --rm -v $(pwd)/secrets:/secrets airbyte/source-harvest:dev discover --config /secrets/config.json docker run --rm -v $(pwd)/secrets:/secrets -v $(pwd)/integration_tests:/integration_tests airbyte/source-harvest:dev read --config /secrets/config.json --catalog /integration_tests/configured_catalog.json ``` -### Running our CI test suite +### Running the CI test suite You can run our full test suite locally using [`airbyte-ci`](https://github.com/airbytehq/airbyte/blob/master/airbyte-ci/connectors/pipelines/README.md): @@ -72,33 +51,15 @@ You can run our full test suite locally using [`airbyte-ci`](https://github.com/ airbyte-ci connectors --name=source-harvest test ``` -### Customizing acceptance Tests - -Customize `acceptance-test-config.yml` file to configure acceptance tests. See [Connector Acceptance Tests](https://docs.airbyte.com/connector-development/testing-connectors/connector-acceptance-tests-reference) for more information. -If your connector requires to create or destroy resources for use during acceptance tests create fixtures for it and place them inside integration_tests/acceptance.py. - -### Dependency Management - -All of your dependencies should be managed via Poetry. -To add a new dependency, run: - -```bash -poetry add -``` - -Please commit the changes to `pyproject.toml` and `poetry.lock` files. - ## Publishing a new version of the connector -You've checked out the repo, implemented a million dollar feature, and you're ready to share your changes with the world. Now what? - -1. Make sure your changes are passing our test suite: `airbyte-ci connectors --name=source-harvest test` -2. Bump the connector version (please follow [semantic versioning for connectors](https://docs.airbyte.com/contributing-to-airbyte/resources/pull-requests-handbook/#semantic-versioning-for-connectors)): - - bump the `dockerImageTag` value in in `metadata.yaml` - - bump the `version` value in `pyproject.toml` -3. Make sure the `metadata.yaml` content is up to date. +If you want to contribute changes to `source-harvest`, here's how you can do that: +1. Make your changes locally, or load the connector's manifest into Connector Builder and make changes there. +2. Make sure your changes are passing our test suite with `airbyte-ci connectors --name=source-harvest test` +3. Bump the connector version (please follow [semantic versioning for connectors](https://docs.airbyte.com/contributing-to-airbyte/resources/pull-requests-handbook/#semantic-versioning-for-connectors)): + - bump the `dockerImageTag` value in in `metadata.yaml` 4. Make sure the connector documentation and its changelog is up to date (`docs/integrations/sources/harvest.md`). 5. Create a Pull Request: use [our PR naming conventions](https://docs.airbyte.com/contributing-to-airbyte/resources/pull-requests-handbook/#pull-request-title-convention). 6. Pat yourself on the back for being an awesome contributor. 7. Someone from Airbyte will take a look at your PR and iterate with you to merge it into master. -8. Once your PR is merged, the new version of the connector will be automatically published to Docker Hub and our connector registry. +8. Once your PR is merged, the new version of the connector will be automatically published to Docker Hub and our connector registry. \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-harvest/acceptance-test-config.yml b/airbyte-integrations/connectors/source-harvest/acceptance-test-config.yml index 46c1472ab0e5..f513f6ee6fc1 100644 --- a/airbyte-integrations/connectors/source-harvest/acceptance-test-config.yml +++ b/airbyte-integrations/connectors/source-harvest/acceptance-test-config.yml @@ -3,7 +3,7 @@ test_strictness_level: "high" acceptance_tests: spec: tests: - - spec_path: "source_harvest/spec.yaml" + - spec_path: "manifest.yaml" connection: tests: - config_path: "secrets/config_oauth.json" diff --git a/airbyte-integrations/connectors/source-harvest/main.py b/airbyte-integrations/connectors/source-harvest/main.py deleted file mode 100644 index e00a49b587fd..000000000000 --- a/airbyte-integrations/connectors/source-harvest/main.py +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from source_harvest.run import run - -if __name__ == "__main__": - run() diff --git a/airbyte-integrations/connectors/source-harvest/manifest.yaml b/airbyte-integrations/connectors/source-harvest/manifest.yaml new file mode 100644 index 000000000000..4417e3073c81 --- /dev/null +++ b/airbyte-integrations/connectors/source-harvest/manifest.yaml @@ -0,0 +1,5741 @@ +version: 5.11.1 + +type: DeclarativeSource + +check: + type: CheckStream + stream_names: + - company + +definitions: + streams: + clients: + type: DeclarativeStream + name: clients + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /clients + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - clients + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/clients" + company: + type: DeclarativeStream + name: company + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /company + http_method: GET + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: [] + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/company" + contacts: + type: DeclarativeStream + name: contacts + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /contacts + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - contacts + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/contacts" + estimate_item_categories: + type: DeclarativeStream + name: estimate_item_categories + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /estimate_item_categories + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - estimate_item_categories + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/estimate_item_categories" + estimates: + type: DeclarativeStream + name: estimates + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /estimates + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - estimates + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/estimates" + expense_categories: + type: DeclarativeStream + name: expense_categories + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /expense_categories + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - expense_categories + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/expense_categories" + expenses: + type: DeclarativeStream + name: expenses + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /expenses + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - expenses + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/expenses" + invoice_item_categories: + type: DeclarativeStream + name: invoice_item_categories + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /invoice_item_categories + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - invoice_item_categories + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/invoice_item_categories" + invoices: + type: DeclarativeStream + name: invoices + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /invoices + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - invoices + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/invoices" + projects: + type: DeclarativeStream + name: projects + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /projects + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - projects + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/projects" + roles: + type: DeclarativeStream + name: roles + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /roles + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - roles + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/roles" + task_assignments: + type: DeclarativeStream + name: task_assignments + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /task_assignments + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - task_assignments + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/task_assignments" + tasks: + type: DeclarativeStream + name: tasks + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /tasks + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - tasks + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/tasks" + time_entries: + type: DeclarativeStream + name: time_entries + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /time_entries + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - time_entries + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/time_entries" + user_assignments: + type: DeclarativeStream + name: user_assignments + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /user_assignments + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - user_assignments + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/user_assignments" + users: + type: DeclarativeStream + name: users + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /users + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - users + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/users" + expenses_categories: + type: DeclarativeStream + name: expenses_categories + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /reports/expenses/categories + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - results + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: to + cursor_datetime_formats: + - "%Y%m%d" + datetime_format: "%Y%m%d" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: from + inject_into: request_parameter + end_time_option: + type: RequestOption + field_name: to + inject_into: request_parameter + end_datetime: + type: MinMaxDatetime + datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + step: P365D + cursor_granularity: P1D + transformations: + - type: AddFields + fields: + - path: + - from + value: "\"{{ stream_partition.start_time }}\"" + - type: AddFields + fields: + - path: + - to + value: "\"{{ stream_partition.end_time }}\"" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/expenses_categories" + expenses_clients: + type: DeclarativeStream + name: expenses_clients + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /reports/expenses/clients + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - results + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: to + cursor_datetime_formats: + - "%Y%m%d" + datetime_format: "%Y%m%d" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: from + inject_into: request_parameter + end_time_option: + type: RequestOption + field_name: to + inject_into: request_parameter + end_datetime: + type: MinMaxDatetime + datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + step: P365D + cursor_granularity: P1D + transformations: + - type: AddFields + fields: + - path: + - from + value: "\"{{ stream_partition.start_time }}\"" + - type: AddFields + fields: + - path: + - to + value: "\"{{ stream_partition.end_time }}\"" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/expenses_clients" + expenses_projects: + type: DeclarativeStream + name: expenses_projects + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /reports/expenses/projects + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - results + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: to + cursor_datetime_formats: + - "%Y%m%d" + datetime_format: "%Y%m%d" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: from + inject_into: request_parameter + end_time_option: + type: RequestOption + field_name: to + inject_into: request_parameter + end_datetime: + type: MinMaxDatetime + datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + step: P365D + cursor_granularity: P1D + transformations: + - type: AddFields + fields: + - path: + - from + value: "\"{{ stream_partition.start_time }}\"" + - type: AddFields + fields: + - path: + - to + value: "\"{{ stream_partition.end_time }}\"" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/expenses_projects" + expenses_team: + type: DeclarativeStream + name: expenses_team + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /reports/expenses/team + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - results + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: to + cursor_datetime_formats: + - "%Y%m%d" + datetime_format: "%Y%m%d" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: from + inject_into: request_parameter + end_time_option: + type: RequestOption + field_name: to + inject_into: request_parameter + end_datetime: + type: MinMaxDatetime + datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + step: P365D + cursor_granularity: P1D + transformations: + - type: AddFields + fields: + - path: + - from + value: "\"{{ stream_partition.start_time }}\"" + - type: AddFields + fields: + - path: + - to + value: "\"{{ stream_partition.end_time }}\"" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/expenses_team" + project_budget: + type: DeclarativeStream + name: project_budget + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /reports/project_budget + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - results + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/project_budget" + time_clients: + type: DeclarativeStream + name: time_clients + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /reports/time/clients + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - results + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: to + cursor_datetime_formats: + - "%Y%m%d" + datetime_format: "%Y%m%d" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: from + inject_into: request_parameter + end_time_option: + type: RequestOption + field_name: to + inject_into: request_parameter + end_datetime: + type: MinMaxDatetime + datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + step: P365D + cursor_granularity: P1D + transformations: + - type: AddFields + fields: + - path: + - from + value: "\"{{ stream_partition.start_time }}\"" + - type: AddFields + fields: + - path: + - to + value: "\"{{ stream_partition.end_time }}\"" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/time_clients" + time_projects: + type: DeclarativeStream + name: time_projects + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /reports/time/projects + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - results + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: to + cursor_datetime_formats: + - "%Y%m%d" + datetime_format: "%Y%m%d" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: from + inject_into: request_parameter + end_time_option: + type: RequestOption + field_name: to + inject_into: request_parameter + end_datetime: + type: MinMaxDatetime + datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + step: P365D + cursor_granularity: P1D + transformations: + - type: AddFields + fields: + - path: + - from + value: "\"{{ stream_partition.start_time }}\"" + - type: AddFields + fields: + - path: + - to + value: "\"{{ stream_partition.end_time }}\"" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/time_projects" + time_tasks: + type: DeclarativeStream + name: time_tasks + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /reports/time/tasks + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - results + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: to + cursor_datetime_formats: + - "%Y%m%d" + datetime_format: "%Y%m%d" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: from + inject_into: request_parameter + end_time_option: + type: RequestOption + field_name: to + inject_into: request_parameter + end_datetime: + type: MinMaxDatetime + datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + step: P365D + cursor_granularity: P1D + transformations: + - type: AddFields + fields: + - path: + - from + value: "\"{{ stream_partition.start_time }}\"" + - type: AddFields + fields: + - path: + - to + value: "\"{{ stream_partition.end_time }}\"" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/time_tasks" + time_team: + type: DeclarativeStream + name: time_team + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /reports/time/team + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - results + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: to + cursor_datetime_formats: + - "%Y%m%d" + datetime_format: "%Y%m%d" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: from + inject_into: request_parameter + end_time_option: + type: RequestOption + field_name: to + inject_into: request_parameter + end_datetime: + type: MinMaxDatetime + datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + step: P365D + cursor_granularity: P1D + transformations: + - type: AddFields + fields: + - path: + - from + value: "\"{{ stream_partition.start_time }}\"" + - type: AddFields + fields: + - path: + - to + value: "\"{{ stream_partition.end_time }}\"" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/time_team" + uninvoiced: + type: DeclarativeStream + name: uninvoiced + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /reports/uninvoiced + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - results + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: to + cursor_datetime_formats: + - "%Y%m%d" + datetime_format: "%Y%m%d" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: from + inject_into: request_parameter + end_time_option: + type: RequestOption + field_name: to + inject_into: request_parameter + end_datetime: + type: MinMaxDatetime + datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + step: P365D + cursor_granularity: P1D + transformations: + - type: AddFields + fields: + - path: + - from + value: "\"{{ stream_partition.start_time }}\"" + - type: AddFields + fields: + - path: + - to + value: "\"{{ stream_partition.end_time }}\"" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/uninvoiced" + estimate_messages: + type: DeclarativeStream + name: estimate_messages + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /estimates/{{stream_partition.id}}/messages + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - estimate_messages + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + partition_router: + type: SubstreamPartitionRouter + parent_stream_configs: + - type: ParentStreamConfig + parent_key: id + partition_field: id + stream: + $ref: "#/definitions/streams/estimates" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + transformations: + - type: AddFields + fields: + - path: + - parent_id + value: "{{stream_partition.id}}" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/estimate_messages" + invoice_messages: + type: DeclarativeStream + name: invoice_messages + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /invoices/{{stream_partition.id}}/messages + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - invoice_messages + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + partition_router: + type: SubstreamPartitionRouter + parent_stream_configs: + - type: ParentStreamConfig + parent_key: id + partition_field: id + stream: + $ref: "#/definitions/streams/invoices" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + transformations: + - type: AddFields + fields: + - path: + - parent_id + value: "{{stream_partition.id}}" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/invoice_messages" + invoice_payments: + type: DeclarativeStream + name: invoice_payments + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /invoices/{{stream_partition.id}}/payments + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - invoice_payments + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + partition_router: + type: SubstreamPartitionRouter + parent_stream_configs: + - type: ParentStreamConfig + parent_key: id + partition_field: id + stream: + $ref: "#/definitions/streams/invoices" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + transformations: + - type: AddFields + fields: + - path: + - parent_id + value: "{{stream_partition.id}}" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/invoice_payments" + project_assignments: + type: DeclarativeStream + name: project_assignments + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /users/{{stream_partition.id}}/project_assignments + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - project_assignments + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + partition_router: + type: SubstreamPartitionRouter + parent_stream_configs: + - type: ParentStreamConfig + parent_key: id + partition_field: id + stream: + $ref: "#/definitions/streams/users" + incremental_sync: + type: DatetimeBasedCursor + cursor_field: updated_at + cursor_datetime_formats: + - "%Y-%m-%dT%H:%M:%SZ" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_datetime: + type: MinMaxDatetime + datetime: "{{ config[\"replication_start_date\"] }}" + datetime_format: "%Y-%m-%dT%H:%M:%SZ" + start_time_option: + type: RequestOption + field_name: updated_since + inject_into: request_parameter + transformations: + - type: AddFields + fields: + - path: + - parent_id + value: "{{stream_partition.id}}" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/project_assignments" + billable_rates: + type: DeclarativeStream + name: billable_rates + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /users/{{stream_partition['id']}}/billable_rates + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - billable_rates + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + partition_router: + type: SubstreamPartitionRouter + parent_stream_configs: + - type: ParentStreamConfig + parent_key: id + partition_field: id + stream: + $ref: "#/definitions/streams/users" + transformations: + - type: AddFields + fields: + - path: + - parent_id + value: "{{stream_partition.id}}" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/billable_rates" + cost_rates: + type: DeclarativeStream + name: cost_rates + primary_key: + - id + retriever: + type: SimpleRetriever + requester: + $ref: "#/definitions/base_requester" + path: /users/{{stream_partition.id}}/cost_rates + http_method: GET + request_parameters: + per_page: "50" + request_headers: + Harvest-Account-Id: "{{ config['account_id'] }}" + error_handler: + type: CompositeErrorHandler + error_handlers: + - type: DefaultErrorHandler + backoff_strategies: + - type: WaitTimeFromHeader + header: Retry-After + - type: DefaultErrorHandler + response_filters: + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 401 + error_message: Please ensure your credentials are valid. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 403 + error_message: >- + This is most likely due to insufficient permissions on the + credentials in use. + - type: HttpResponseFilter + action: IGNORE + http_codes: + - 404 + error_message: >- + Please ensure that your account ID is properly set. If it + is the case and you are still seeing this error, please + contact Airbyte support. + record_selector: + type: RecordSelector + extractor: + type: DpathExtractor + field_path: + - cost_rates + paginator: + type: DefaultPaginator + page_token_option: + type: RequestPath + pagination_strategy: + type: CursorPagination + page_size: 1 + cursor_value: "{{ response.get(\"links\", {}).get(\"next\", {}) }}" + stop_condition: "{{ not response.get(\"links\", {}).get(\"next\", {}) }}" + partition_router: + type: SubstreamPartitionRouter + parent_stream_configs: + - type: ParentStreamConfig + parent_key: id + partition_field: id + stream: + $ref: "#/definitions/streams/users" + transformations: + - type: AddFields + fields: + - path: + - parent_id + value: "{{stream_partition.id}}" + schema_loader: + type: InlineSchemaLoader + schema: + $ref: "#/schemas/cost_rates" + base_requester: + type: HttpRequester + url_base: https://api.harvestapp.com/v2/ + authenticator: + type: SelectiveAuthenticator + authenticators: + Token: + type: BearerAuthenticator + api_token: "{{ config['credentials']['api_token'] }}" + Client: + type: OAuthAuthenticator + client_id: "{{ config['credentials']['client_id'] }}" + grant_type: refresh_token + client_secret: "{{ config['credentials']['client_secret'] }}" + refresh_token: "{{ config['credentials']['refresh_token'] }}" + refresh_request_body: {} + token_refresh_endpoint: https://id.getharvest.com/api/v2/oauth2/token + authenticator_selection_path: + - credentials + - auth_type + +streams: + - $ref: "#/definitions/streams/clients" + - $ref: "#/definitions/streams/company" + - $ref: "#/definitions/streams/contacts" + - $ref: "#/definitions/streams/estimate_item_categories" + - $ref: "#/definitions/streams/estimates" + - $ref: "#/definitions/streams/expense_categories" + - $ref: "#/definitions/streams/expenses" + - $ref: "#/definitions/streams/invoice_item_categories" + - $ref: "#/definitions/streams/invoices" + - $ref: "#/definitions/streams/projects" + - $ref: "#/definitions/streams/roles" + - $ref: "#/definitions/streams/task_assignments" + - $ref: "#/definitions/streams/tasks" + - $ref: "#/definitions/streams/time_entries" + - $ref: "#/definitions/streams/user_assignments" + - $ref: "#/definitions/streams/users" + - $ref: "#/definitions/streams/expenses_categories" + - $ref: "#/definitions/streams/expenses_clients" + - $ref: "#/definitions/streams/expenses_projects" + - $ref: "#/definitions/streams/expenses_team" + - $ref: "#/definitions/streams/project_budget" + - $ref: "#/definitions/streams/time_clients" + - $ref: "#/definitions/streams/time_projects" + - $ref: "#/definitions/streams/time_tasks" + - $ref: "#/definitions/streams/time_team" + - $ref: "#/definitions/streams/uninvoiced" + - $ref: "#/definitions/streams/estimate_messages" + - $ref: "#/definitions/streams/invoice_messages" + - $ref: "#/definitions/streams/invoice_payments" + - $ref: "#/definitions/streams/project_assignments" + - $ref: "#/definitions/streams/billable_rates" + - $ref: "#/definitions/streams/cost_rates" + +spec: + type: Spec + connection_specification: + type: object + $schema: http://json-schema.org/draft-07/schema# + required: + - account_id + - replication_start_date + properties: + account_id: + type: string + description: >- + Harvest account ID. Required for all Harvest requests in pair with + Personal Access Token + order: 0 + title: Account ID + airbyte_secret: true + replication_start_date: + type: string + description: >- + UTC date and time in the format 2017-01-25T00:00:00Z. Any data before + this date will not be replicated. + order: 1 + title: Start Date + format: date-time + pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ + examples: + - "2017-01-25T00:00:00Z" + replication_end_date: + type: string + description: >- + UTC date and time in the format 2017-01-25T00:00:00Z. Any data after + this date will not be replicated. + order: 2 + title: End Date + format: date-time + pattern: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ + examples: + - "2017-01-25T00:00:00Z" + airbyte_hidden: true + credentials: + type: object + description: Choose how to authenticate to Harvest. + oneOf: + - type: object + title: Authenticate via Harvest (OAuth) + required: + - client_id + - client_secret + - refresh_token + properties: + auth_type: + type: string + const: Client + order: 0 + client_id: + type: string + description: The Client ID of your Harvest developer application. + title: Client ID + client_secret: + type: string + description: The Client Secret of your Harvest developer application. + title: Client Secret + airbyte_secret: true + refresh_token: + type: string + description: Refresh Token to renew the expired Access Token. + title: Refresh Token + airbyte_secret: true + additionalProperties: true + - type: object + title: Authenticate with Personal Access Token + required: + - api_token + properties: + api_token: + type: string + description: >- + Log into Harvest and then create new personal access + token. + title: Personal Access Token + airbyte_secret: true + auth_type: + type: string + const: Token + order: 0 + additionalProperties: true + order: 3 + title: Authentication mechanism + additionalProperties: true + +metadata: + autoImportSchema: + clients: true + company: true + contacts: true + estimate_item_categories: true + estimates: true + expense_categories: true + expenses: true + invoice_item_categories: true + invoices: true + projects: true + roles: true + task_assignments: false + tasks: true + time_entries: true + user_assignments: true + users: true + expenses_categories: true + expenses_clients: true + expenses_projects: true + expenses_team: true + project_budget: true + time_clients: true + time_projects: true + time_tasks: true + time_team: true + uninvoiced: true + estimate_messages: true + invoice_messages: true + invoice_payments: true + project_assignments: true + billable_rates: true + cost_rates: true + yamlComponents: + streams: + clients: + - errorHandler + contacts: + - errorHandler + estimate_item_categories: + - errorHandler + estimates: + - errorHandler + expense_categories: + - errorHandler + expenses: + - errorHandler + invoice_item_categories: + - errorHandler + invoices: + - errorHandler + projects: + - errorHandler + roles: + - errorHandler + task_assignments: + - errorHandler + tasks: + - errorHandler + time_entries: + - errorHandler + user_assignments: + - errorHandler + users: + - errorHandler + expenses_categories: + - errorHandler + expenses_clients: + - errorHandler + expenses_projects: + - errorHandler + expenses_team: + - errorHandler + project_budget: + - errorHandler + time_clients: + - errorHandler + time_projects: + - errorHandler + time_tasks: + - errorHandler + time_team: + - errorHandler + uninvoiced: + - errorHandler + estimate_messages: + - errorHandler + invoice_messages: + - errorHandler + invoice_payments: + - errorHandler + project_assignments: + - errorHandler + billable_rates: + - errorHandler + cost_rates: + - errorHandler + global: + - authenticator + testedStreams: + clients: + streamHash: d8cdaf88743431e6801dc200b825b6782e9605fc + company: + streamHash: 325af6ff2e0552d3886de054a2e8e08741852d13 + contacts: + streamHash: 460078560a6001d88c2a23272b714f61216c2b7d + estimate_item_categories: + streamHash: 06c8c133acf78e0483e62e7bd65e97abc93e075d + estimates: + streamHash: 1507b989e277d64bb259d3038fd3d4830ae2ca49 + expense_categories: + streamHash: add93bd75365c43dde1724861f65c53d0d82ea2e + expenses: + streamHash: 7e2b841580128b8ca3fc2b4e9296993cba366cf6 + invoice_item_categories: + streamHash: 14725d0427e26ce35803a0b81e612874b15efc58 + invoices: + streamHash: 6b774bfe7b4be9d0ec330eb61883b2a917df4190 + projects: + streamHash: f140b764c5712b325e0398d50d7cbb7e5c5a2b22 + roles: + streamHash: 26be31d04bffbacc601e85046a4accd0cf9cf37e + task_assignments: + streamHash: 56de2110fd110723cb28f21452fce7e8cfe6ff72 + tasks: + streamHash: 0b5f2a6617271dc2788d0797f5eae99f6ae9c676 + time_entries: + streamHash: a739c04ee5636e21be16c6780a0a44144d48765f + user_assignments: + streamHash: 071df4020a4e86042537aca5c83e3568a9741995 + users: + streamHash: d2dbbb89b201e0ec44516e7611acbbbd1ca28c5f + expenses_categories: + streamHash: 5ddb6bbbfee7a39b8d744db1d134c5ebeab3f2e7 + expenses_clients: + streamHash: d9e94401d2285d9458cd6bd4bcd69f2afdaabb5c + expenses_projects: + streamHash: cacaff590966970fb603a92a9cd924e2657b4e48 + expenses_team: + streamHash: 23745b850e9efca2a96555b3c85f486ab74b5e49 + project_budget: + streamHash: 4a1b588ca4fc2572aeed358d279b24b71ea63aa9 + time_clients: + streamHash: e598bd5763ec7eaae357564cd163299649d7ec83 + time_projects: + streamHash: b54310cc4a4c966f9a92c51ae5386d72f94e8ed7 + time_tasks: + streamHash: f4568a104accd94bb4b0a1f7a7bc19df52291439 + time_team: + streamHash: 3e0a61862dd6d0af0f5d13fd2f93331e86b3417c + uninvoiced: + streamHash: ec3cee771ba8d252b1c124f6b5915f6a1889f0e6 + estimate_messages: + streamHash: 79928af30431f4925a1e11897674dcdb1bad8f7a + invoice_messages: + streamHash: 157ca8bb671c6b81ec7e9e356df356fcb867773f + invoice_payments: + streamHash: 915604f1f279b7317f8a078ecc8b3ae22d18c79f + project_assignments: + streamHash: f78913890dcddfcf824f3b30a2c0f2c32af49bf3 + billable_rates: + streamHash: 38a21d690af221346e778d17fdd50235c66aed44 + cost_rates: + streamHash: 2b5d8b57636cd60bd055a3dbfe194d32b3264c28 + assist: {} + +schemas: + clients: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + address: + type: + - "null" + - string + description: The client's postal address. + created_at: + type: + - "null" + - string + description: The date and time when the client record was created. + format: date-time + currency: + type: + - "null" + - string + description: The currency used by the client. + id: + type: + - "null" + - integer + description: Unique identifier for the client. + is_active: + type: + - "null" + - boolean + description: Indicates whether the client is currently active or not. + name: + type: + - "null" + - string + description: The client's name. + statement_key: + type: + - "null" + - string + description: Key used for client's statements or invoices. + updated_at: + type: + - "null" + - string + description: The date and time when the client record was last updated. + format: date-time + company: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + approval_required: + type: + - "null" + - boolean + description: Indicates if approval is required for certain actions. + base_uri: + type: + - "null" + - string + description: The base URI used in constructing URLs for this company. + clock: + type: + - "null" + - string + description: The clock configuration for time tracking. + color_scheme: + type: + - "null" + - string + description: The color scheme used in the user interface. + decimal_symbol: + type: + - "null" + - string + description: >- + The symbol used to separate the integer part from the fractional part + of a number. + estimate_feature: + type: + - "null" + - boolean + description: Indicates if the estimate feature is enabled for this company. + expense_feature: + type: + - "null" + - boolean + description: Indicates if the expense feature is enabled for this company. + full_domain: + type: + - "null" + - string + description: The full domain name associated with this company. + invoice_feature: + type: + - "null" + - boolean + description: Indicates if the invoice feature is enabled for this company. + is_active: + type: + - "null" + - boolean + description: Indicates if the company is currently active. + name: + type: + - "null" + - string + description: The name of the company. + plan_type: + type: + - "null" + - string + description: The type of plan subscribed by the company. + thousands_separator: + type: + - "null" + - string + description: The symbol used to separate thousands in a number. + time_format: + type: + - "null" + - string + description: The format used to display time. + wants_timestamp_timers: + type: + - "null" + - boolean + description: Indicates if the company wants timestamp timers displayed. + week_start_day: + type: + - "null" + - string + description: The day considered the start of the week for this company. + weekly_capacity: + type: + - "null" + - integer + description: The weekly capacity setting for this company. + contacts: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + client: + type: + - "null" + - object + description: Details of the client associated with the contact + properties: + id: + type: + - "null" + - integer + description: Unique identifier for the client + name: + type: + - "null" + - string + description: Name of the client + created_at: + type: + - "null" + - string + description: Timestamp of when the contact was created + format: date-time + email: + type: + - "null" + - string + description: Email address of the contact + fax: + type: + - "null" + - string + description: Fax number of the contact + first_name: + type: + - "null" + - string + description: First name of the contact + id: + type: + - "null" + - integer + description: Unique identifier for the contact + last_name: + type: + - "null" + - string + description: Last name of the contact + phone_mobile: + type: + - "null" + - string + description: Mobile phone number of the contact + phone_office: + type: + - "null" + - string + description: Office phone number of the contact + title: + type: + - "null" + - string + description: Job title of the contact + updated_at: + type: + - "null" + - string + description: Timestamp of when the contact was last updated + format: date-time + estimate_item_categories: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + created_at: + type: + - "null" + - string + description: The date and time when the estimate item category was created. + format: date-time + id: + type: + - "null" + - integer + description: The unique identifier for the estimate item category. + name: + type: + - "null" + - string + description: The name of the estimate item category. + updated_at: + type: + - "null" + - string + description: The date and time when the estimate item category was last updated. + format: date-time + estimates: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + accepted_at: + type: + - "null" + - string + description: The date and time when the estimates was accepted. + amount: + type: + - "null" + - number + description: The total amount of the estimate. + client: + type: + - "null" + - object + description: Details about the client associated with the estimates + properties: + id: + type: + - "null" + - integer + description: The unique identifier of the client. + name: + type: + - "null" + - string + description: The name of the client. + client_key: + type: + - "null" + - string + description: The key associated with the client. + created_at: + type: + - "null" + - string + description: The date and time when the estimates was created. + format: date-time + creator: + type: + - "null" + - object + description: Information about the creator of the estimates + properties: + id: + type: + - "null" + - integer + description: The unique identifier of the user who created the estimate. + name: + type: + - "null" + - string + description: The name of the user who created the estimate. + currency: + type: + - "null" + - string + description: The currency used for the estimate. + declined_at: + type: + - "null" + - string + description: The date and time when the estimates was declined. + discount: + type: + - "null" + - number + description: The discount percentage applied to the estimate. + discount_amount: + type: + - "null" + - number + description: The total discount amount applied to the estimate. + id: + type: + - "null" + - integer + description: The unique identifier of the estimate. + issue_date: + type: + - "null" + - string + description: The date when the estimate was issued. + format: date + line_items: + type: + - "null" + - array + description: The list of line items included in the estimate. + notes: + type: + - "null" + - string + description: Any additional notes or comments related to the estimate. + number: + type: + - "null" + - string + description: The unique number assigned to the estimate. + purchase_order: + type: + - "null" + - string + description: The purchase order associated with the estimate. + sent_at: + type: + - "null" + - string + description: The date and time when the estimate was sent. + format: date-time + state: + type: + - "null" + - string + description: The current state of the estimate (e.g., pending, accepted, declined). + subject: + type: + - "null" + - string + description: The subject or description of the estimate. + tax: + type: + - "null" + - number + description: The tax rate applied to the estimate. + tax2: + type: + - "null" + - number + description: An additional tax rate applied to the estimate. + tax2_amount: + type: + - "null" + - number + description: The total amount of the additional tax applied to the estimate. + tax_amount: + type: + - "null" + - number + description: The total amount of tax applied to the estimate. + updated_at: + type: + - "null" + - string + description: The date and time when the estimate was last updated. + format: date-time + expense_categories: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + created_at: + type: + - "null" + - string + description: The date and time when the expense category was created. + format: date-time + id: + type: + - "null" + - integer + description: The unique identifier for the expense category. + is_active: + type: + - "null" + - boolean + description: Indicates whether the expense category is currently active or not. + name: + type: + - "null" + - string + description: The name of the expense category. + unit_name: + type: + - "null" + - string + description: The unit of measurement for the expense category. + unit_price: + type: + - "null" + - number + description: The price per unit of the expense category. + updated_at: + type: + - "null" + - string + description: The date and time when the expense category was last updated. + format: date-time + expenses: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable: + type: + - "null" + - boolean + description: Indicates if the expense is billable to the client + client: + type: + - "null" + - object + description: Details of the client associated with the expense + properties: + currency: + type: + - "null" + - string + description: Currency used for the client's transactions + id: + type: + - "null" + - integer + description: Unique identifier for the client + name: + type: + - "null" + - string + description: Name of the client associated with the expense + created_at: + type: + - "null" + - string + description: Date and time when the expense was created + format: date-time + expense_category: + type: + - "null" + - object + description: Information about the category of the expense + properties: + id: + type: + - "null" + - integer + description: Unique identifier for the expense category + name: + type: + - "null" + - string + description: Name of the expense category + unit_name: + type: + - "null" + - string + description: Name of the unit (if applicable) + unit_price: + type: + - "null" + - number + description: Price per unit (if applicable) + id: + type: + - "null" + - integer + description: Unique identifier for the expense entry + invoice: + type: + - "null" + - object + description: Details of the invoice related to the expense + properties: + id: + type: + - "null" + - integer + description: Unique identifier for the invoice associated with the expense + number: + type: + - "null" + - string + description: Invoice number related to the expense + is_billed: + type: + - "null" + - boolean + description: Indicates if the expense has been billed to the client + is_closed: + type: + - "null" + - boolean + description: Indicates if the expense entry is closed + is_locked: + type: + - "null" + - boolean + description: Indicates if the expense entry is locked + locked_reason: + type: + - "null" + - string + description: Reason for locking the expense entry + notes: + type: + - "null" + - string + description: Additional notes or comments for the expense entry + project: + type: + - "null" + - object + description: Information about the project for which the expense was made + properties: + code: + type: + - "null" + - string + description: Code associated with the project + id: + type: + - "null" + - integer + description: Unique identifier for the project + name: + type: + - "null" + - string + description: Name of the project associated with the expense + receipt: + type: + - "null" + - object + description: Details of the receipt attached to the expense + properties: + content_type: + type: + - "null" + - string + description: MIME type of the receipt content + file_name: + type: + - "null" + - string + description: Name of the receipt file + file_size: + type: + - "null" + - integer + description: Size of the receipt file + url: + type: + - "null" + - string + description: URL path to access the receipt file + spent_date: + type: + - "null" + - string + description: Date when the expense was incurred + format: date + total_cost: + type: + - "null" + - number + description: Total cost of the expense entry + units: + type: + - "null" + - number + description: Number of units (if applicable) + updated_at: + type: + - "null" + - string + description: Date and time of the last update to the expense entry + format: date-time + user: + type: + - "null" + - object + description: Information about the user who incurred the expense + properties: + id: + type: + - "null" + - integer + description: Unique identifier for the user + name: + type: + - "null" + - string + description: Name of the user who incurred the expense + user_assignment: + type: + - "null" + - object + description: Details of the assignment or task associated with the expense + properties: + budget: + type: + - "null" + - number + description: Budget allocated for the user assignment + created_at: + type: + - "null" + - string + description: Date and time when the user assignment was created + format: date-time + hourly_rate: + type: + - "null" + - number + description: Hourly rate set for the user assignment + id: + type: + - "null" + - integer + description: Unique identifier for the user assignment + is_active: + type: + - "null" + - boolean + description: Indicates if the user assignment is active + is_project_manager: + type: + - "null" + - boolean + description: Indicates if the user is a project manager + updated_at: + type: + - "null" + - string + description: Date and time of the last update to the user assignment + format: date-time + use_default_rates: + type: + - "null" + - boolean + description: Indicates if default rates are used for the user assignment + invoice_item_categories: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + created_at: + type: + - "null" + - string + description: The date and time when the invoice item category was created. + format: date-time + id: + type: + - "null" + - integer + description: The unique identifier for the invoice item category. + name: + type: + - "null" + - string + description: The name of the invoice item category. + updated_at: + type: + - "null" + - string + description: The date and time when the invoice item category was last updated. + format: date-time + use_as_expense: + type: + - "null" + - boolean + description: Indicates whether the category is used as an expense type. + use_as_service: + type: + - "null" + - boolean + description: Indicates whether the category is used as a service type. + invoices: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + amount: + type: + - "null" + - number + description: The total amount of the invoice + client: + type: + - "null" + - object + description: Details of the client associated with the invoice + properties: + id: + type: + - "null" + - integer + description: The unique identifier of the client + name: + type: + - "null" + - string + description: The name of the client + client_key: + type: + - "null" + - string + description: Key associated with the client + closed_at: + type: + - "null" + - string + description: Timestamp when the invoice was closed + created_at: + type: + - "null" + - string + description: Timestamp when the invoice was created + format: date-time + creator: + type: + - "null" + - object + description: Information about the creator of the invoice + properties: + id: + type: + - "null" + - integer + description: The unique identifier of the creator + name: + type: + - "null" + - string + description: The name of the creator + currency: + type: + - "null" + - string + description: The currency used for the invoice + discount: + type: + - "null" + - number + description: Discount percentage applied to the invoice + discount_amount: + type: + - "null" + - number + description: The total discount amount applied + due_amount: + type: + - "null" + - number + description: The remaining amount that is due + due_date: + type: + - "null" + - string + description: Due date for the invoice payment + estimate: + type: + - "null" + - string + description: Whether the invoice is an estimate + id: + type: + - "null" + - integer + description: The unique identifier of the invoice + issue_date: + type: + - "null" + - string + description: Date when the invoice was issued + line_items: + type: + - "null" + - array + description: >- + List of line items containing the services/products included in the + invoice + items: + type: + - "null" + - object + properties: + description: + type: + - "null" + - string + description: Description of the line item + amount: + type: + - "null" + - number + description: The amount per line item + id: + type: + - "null" + - integer + description: The unique identifier of the line item + kind: + type: + - "null" + - string + description: Type of line item + project: + type: + - "null" + - object + description: Details of the project related to the line item + properties: + code: + type: + - "null" + - string + description: Project code of the line item + id: + type: + - integer + - "null" + description: The unique identifier of the project + name: + type: + - "null" + - string + description: Name of the project + quantity: + type: + - "null" + - number + description: Quantity of the line item + taxed: + type: + - "null" + - boolean + description: Whether the line item is taxed + taxed2: + type: + - "null" + - boolean + description: Whether the line item is taxed at a different rate + unit_price: + type: + - "null" + - number + description: Unit price of the line item + notes: + type: + - "null" + - string + description: Additional notes related to the invoice + number: + type: + - "null" + - string + description: Invoice number + paid_at: + type: + - "null" + - string + description: Timestamp when the invoice was paid + paid_date: + type: + - "null" + - string + description: Date when the invoice was paid + payment_options: + type: + - "null" + - array + description: Payment options available for the invoice + payment_term: + type: + - "null" + - string + description: Payment terms associated with the invoice + period_end: + type: + - "null" + - string + description: End date of the period covered by the invoice + period_start: + type: + - "null" + - string + description: Start date of the period covered by the invoice + purchase_order: + type: + - "null" + - string + description: Purchase order related to the invoice + recurring_invoice_id: + type: + - "null" + - string + description: Unique identifier of the recurring invoice + retainer: + type: + - "null" + - string + description: Whether the invoice is for a retainer + sent_at: + type: + - "null" + - string + description: Timestamp when the invoice was sent + format: date-time + state: + type: + - "null" + - string + description: Current state of the invoice + subject: + type: + - "null" + - string + description: Subject of the invoice + tax: + type: + - "null" + - number + description: Tax amount applied + tax2: + type: + - "null" + - number + description: Additional tax amount applied at a different rate + tax2_amount: + type: + - "null" + - number + description: Total amount of tax2 applied + tax_amount: + type: + - "null" + - number + description: Total amount of tax applied + updated_at: + type: + - "null" + - string + description: Timestamp when the invoice was last updated + format: date-time + projects: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + bill_by: + type: + - "null" + - string + description: Indicates how the project is billed, e.g., hourly, fixed fee, etc. + budget: + type: + - "null" + - number + description: The allocated budget for the project. + budget_by: + type: + - "null" + - string + description: Specifies how the budget is managed, e.g., total, task, person, etc. + budget_is_monthly: + type: + - "null" + - boolean + description: Indicates whether the budget is monthly. + client: + type: + - "null" + - object + description: Details of the client associated with the project. + properties: + currency: + type: + - "null" + - string + description: The currency used for the project. + id: + type: + - "null" + - integer + description: The unique identifier of the client. + name: + type: + - "null" + - string + description: The name of the client associated with the project. + code: + type: + - "null" + - string + description: A unique identifier or code for the project. + cost_budget: + type: + - "null" + - number + description: The total cost budget for the project. + cost_budget_include_expenses: + type: + - "null" + - boolean + description: Indicates whether expenses are included in the cost budget. + created_at: + type: + - "null" + - string + description: The date and time when the project was created. + format: date-time + ends_on: + type: + - "null" + - string + description: The end date of the project. + fee: + type: + - "null" + - number + description: The fee associated with the project. + hourly_rate: + type: + - "null" + - number + description: The hourly rate for the project. + id: + type: + - "null" + - integer + description: The unique identifier of the project. + is_active: + type: + - "null" + - boolean + description: Indicates whether the project is currently active. + is_billable: + type: + - "null" + - boolean + description: Indicates whether the project is billable. + is_fixed_fee: + type: + - "null" + - boolean + description: Indicates whether the project has a fixed fee. + name: + type: + - "null" + - string + description: The name or title of the project. + notes: + type: + - "null" + - string + description: Any additional notes or comments related to the project. + notify_when_over_budget: + type: + - "null" + - boolean + description: >- + Indicates whether notifications are sent when the project goes over + budget. + over_budget_notification_date: + type: + - "null" + - string + description: The date for sending notifications when the project goes over budget. + format: date + over_budget_notification_percentage: + type: + - "null" + - number + description: The percentage threshold for over-budget notifications. + show_budget_to_all: + type: + - "null" + - boolean + description: Indicates whether the budget is visible to all project members. + starts_on: + type: + - "null" + - string + description: The start date of the project. + format: date + updated_at: + type: + - "null" + - string + description: The date and time when the project was last updated. + format: date-time + roles: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + created_at: + type: + - "null" + - string + description: The date and time when the role was created + format: date-time + id: + type: + - "null" + - integer + description: The unique identifier for the role + name: + type: + - "null" + - string + description: The name of the role + updated_at: + type: + - "null" + - string + description: The date and time when the role was last updated + format: date-time + user_ids: + type: + - "null" + - array + description: An array of user IDs associated with the role + items: + type: integer + description: The unique identifier for a user assigned to this role + task_assignments: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable: + type: + - "null" + - boolean + description: Indicates if the task assignment is billable or not + budget: + type: + - "null" + - string + description: The budget allocated for this task assignment + created_at: + type: + - "null" + - string + description: The date and time when the task assignment was created + format: date-time + hourly_rate: + type: + - "null" + - number + description: The hourly rate for this task assignment + id: + type: + - "null" + - integer + description: Unique identifier for the task assignment + is_active: + type: + - "null" + - boolean + description: Indicates if the task assignment is currently active + project: + type: + - "null" + - object + description: Details about the project the task assignment is associated with. + properties: + code: + type: + - "null" + - string + description: The code assigned to the project + id: + type: + - "null" + - integer + description: Unique identifier for the project + name: + type: + - "null" + - string + description: The name of the project + task: + type: + - "null" + - object + description: Information related to the task assigned. + properties: + id: + type: + - "null" + - integer + description: Unique identifier for the task + name: + type: + - "null" + - string + description: The name of the task + updated_at: + type: + - "null" + - string + description: The date and time when the task assignment was last updated + format: date-time + tasks: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable_by_default: + type: + - "null" + - boolean + description: Indicates if the task is billable by default for the project. + created_at: + type: + - "null" + - string + description: Timestamp for when the task was created. + format: date-time + default_hourly_rate: + type: + - "null" + - number + description: Default hourly rate set for the task. + id: + type: + - "null" + - integer + description: Unique identifier for the task. + is_active: + type: + - "null" + - boolean + description: Indicates if the task is active or not. + is_default: + type: + - "null" + - boolean + description: Indicates if the task is the default task for the project. + name: + type: + - "null" + - string + description: Name of the task. + updated_at: + type: + - "null" + - string + description: Timestamp for when the task was last updated. + format: date-time + time_entries: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable: + type: + - "null" + - boolean + description: Indicates if the time entry is billable or not. + billable_rate: + type: + - "null" + - number + description: The rate at which the time entry is billable. + budgeted: + type: + - "null" + - boolean + description: Indicates if the time entry is within the budget. + client: + type: + - "null" + - object + description: The client associated with the time entry + properties: + currency: + type: + - "null" + - string + description: The currency used by the client. + id: + type: + - "null" + - integer + description: The unique identifier of the client. + name: + type: + - "null" + - string + description: The name of the client. + cost_rate: + type: + - "null" + - number + description: The cost rate associated with the time entry. + created_at: + type: + - "null" + - string + description: The date and time when the time entry was created. + format: date-time + ended_time: + type: + - "null" + - string + description: The time when the time entry ended. + external_reference: + type: + - "null" + - string + description: An external reference linked to the time entry. + hours: + type: + - "null" + - number + description: The total hours logged in the time entry. + hours_without_timer: + type: + - "null" + - number + description: Hours logged without using a timer. + id: + type: + - "null" + - integer + description: The unique identifier of the time entry. + invoice: + type: + - "null" + - object + description: The invoice related to the time entry + properties: + id: + type: integer + description: The unique identifier of the associated invoice. + number: + type: string + description: The invoice number associated with the time entry. + is_billed: + type: + - "null" + - boolean + description: Indicates if the time entry has been billed. + is_closed: + type: + - "null" + - boolean + description: Indicates if the time entry is closed. + is_locked: + type: + - "null" + - boolean + description: Indicates if the time entry is locked. + is_running: + type: + - "null" + - boolean + description: Indicates if the time entry is currently running. + locked_reason: + type: + - "null" + - string + description: The reason why the time entry is locked. + notes: + type: + - "null" + - string + description: Any additional notes associated with the time entry. + project: + type: + - "null" + - object + description: The project where the time entry was tracked + properties: + code: + type: + - "null" + - string + description: The project code associated with the time entry. + id: + type: + - "null" + - integer + description: The unique identifier of the project. + name: + type: + - "null" + - string + description: The name of the project. + rounded_hours: + type: + - "null" + - number + description: The total hours rounded to a specific precision. + spent_date: + type: + - "null" + - string + description: The date when the time was spent. + format: date + started_time: + type: + - "null" + - string + description: The time when the time entry started. + task: + type: + - "null" + - object + description: The task performed during the time entry + properties: + id: + type: + - "null" + - integer + description: The unique identifier of the task. + name: + type: + - "null" + - string + description: The name of the task. + task_assignment: + type: + - "null" + - object + description: The task assignment details for the time entry + properties: + billable: + type: + - "null" + - boolean + description: Indicates if the task assignment is billable. + budget: + type: + - "null" + - number + description: The budget associated with the task assignment. + created_at: + type: + - "null" + - string + description: The date and time when the task assignment was created. + format: date-time + hourly_rate: + type: + - "null" + - number + description: The hourly rate associated with the task assignment. + id: + type: + - "null" + - integer + description: The unique identifier of the task assignment. + is_active: + type: + - "null" + - boolean + description: Indicates if the task assignment is active. + updated_at: + type: + - "null" + - string + description: The date and time when the task assignment was last updated. + format: date-time + timer_started_at: + type: + - "null" + - string + description: The time when the timer for the time entry was started. + updated_at: + type: + - "null" + - string + description: The date and time when the time entry was last updated. + format: date-time + user: + type: + - "null" + - object + description: The user who created the time entry + properties: + id: + type: + - "null" + - integer + description: The unique identifier of the user. + name: + type: + - "null" + - string + description: The name of the user. + user_assignment: + type: + - "null" + - object + description: The user assignment details for the time entry + properties: + budget: + type: + - "null" + - number + description: The budget associated with the user assignment. + created_at: + type: + - "null" + - string + description: The date and time when the user assignment was created. + format: date-time + hourly_rate: + type: + - "null" + - number + description: The hourly rate associated with the user assignment. + id: + type: + - "null" + - integer + description: The unique identifier of the user assignment. + is_active: + type: + - "null" + - boolean + description: Indicates if the user assignment is active. + is_project_manager: + type: + - "null" + - boolean + description: Indicates if the user is a project manager. + updated_at: + type: + - "null" + - string + description: The date and time when the user assignment was last updated. + format: date-time + user_assignments: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + budget: + type: + - "null" + - number + description: The budget allocated for the assignment + created_at: + type: + - "null" + - string + description: The date and time when the assignment was created + format: date-time + hourly_rate: + type: + - "null" + - number + description: The hourly rate for the assignment + id: + type: + - "null" + - integer + description: The unique identifier for the assignment + is_active: + type: + - "null" + - boolean + description: Flag indicating if the assignment is currently active + is_project_manager: + type: + - "null" + - boolean + description: Flag indicating if the user is a project manager for the assignment + project: + type: + - "null" + - object + description: Details of the project the user is assigned to. + properties: + code: + type: + - "null" + - string + description: The project code associated with the assignment + id: + type: + - "null" + - integer + description: The unique identifier of the project + name: + type: + - "null" + - string + description: The name of the project associated with the assignment + updated_at: + type: + - "null" + - string + description: The date and time when the assignment was last updated + format: date-time + use_default_rates: + type: + - "null" + - boolean + description: Flag indicating if default rates are used for the assignment + user: + type: + - "null" + - object + description: Details of the user assignment. + properties: + id: + type: + - "null" + - integer + description: The unique identifier of the user assigned to the project + name: + type: + - "null" + - string + description: The name of the user assigned to the project + users: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + avatar_url: + type: + - "null" + - string + description: URL of the user's avatar image. + calendar_integration_enabled: + type: + - "null" + - boolean + description: Indicates if calendar integration is enabled for the user. + calendar_integration_source: + type: + - "null" + - string + description: Source of calendar integration for the user. + can_create_invoices: + type: + - "null" + - boolean + description: Shows if the user can create invoices. + can_create_projects: + type: + - "null" + - boolean + description: Shows if the user can create projects. + can_see_rates: + type: + - "null" + - boolean + description: Indicates if the user can see rates. + cost_rate: + type: + - "null" + - number + description: The cost rate associated with the user. + created_at: + type: + - "null" + - string + description: Date and time when the user was created. + format: date-time + default_hourly_rate: + type: + - "null" + - number + description: User's default hourly rate for billing. + email: + type: + - "null" + - string + description: User's email address. + first_name: + type: + - "null" + - string + description: User's first name. + has_access_to_all_future_projects: + type: + - "null" + - boolean + description: Indicates if the user has access to all future projects. + id: + type: + - "null" + - integer + description: Unique identifier for the user. + is_active: + type: + - "null" + - boolean + description: Shows if the user is currently active. + is_admin: + type: + - "null" + - boolean + description: Indicates if the user is an admin. + is_contractor: + type: + - "null" + - boolean + description: Shows if the user is a contractor. + is_project_manager: + type: + - "null" + - boolean + description: Indicates if the user is a project manager. + last_name: + type: + - "null" + - string + description: User's last name. + roles: + type: + - "null" + - array + description: List of roles associated with the user. + items: + type: string + telephone: + type: + - "null" + - string + description: User's telephone number. + timezone: + type: + - "null" + - string + description: User's timezone. + updated_at: + type: + - "null" + - string + description: Date and time when the user record was last updated. + format: date-time + weekly_capacity: + type: + - "null" + - integer + description: User's weekly capacity for work. + expenses_categories: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable_amount: + type: + - "null" + - number + description: The amount that can be billed to a client for this expense category + currency: + type: + - "null" + - string + description: The currency in which the expenses are incurred + expense_category_id: + type: + - "null" + - integer + description: Unique identifier for the expense category + expense_category_name: + type: + - "null" + - string + description: Name of the expense category + from: + type: + - "null" + - string + description: Start date for the expenses + to: + type: + - "null" + - string + description: End date for the expenses + total_amount: + type: + - "null" + - number + description: Total amount spent on this expense category + expenses_clients: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable_amount: + type: + - "null" + - number + description: The amount billed to the client for the expenses. + client_id: + type: + - "null" + - integer + description: The unique identifier of the client. + client_name: + type: + - "null" + - string + description: The name of the client associated with the expenses. + currency: + type: + - "null" + - string + description: The currency in which the expenses are recorded. + from: + type: + - "null" + - string + description: The start date of the expense period. + to: + type: + - "null" + - string + description: The end date of the expense period. + total_amount: + type: + - "null" + - number + description: >- + The total amount of expenses including billable and non-billable + expenses. + expenses_projects: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable_amount: + type: + - "null" + - number + description: The amount of expenses that are billable to the client + client_id: + type: + - "null" + - integer + description: The unique identifier of the client associated with the project + client_name: + type: + - "null" + - string + description: The name of the client associated with the project + currency: + type: + - "null" + - string + description: The currency in which the expenses are recorded + from: + type: + - "null" + - string + description: The starting date of the expense record period + project_id: + type: + - "null" + - integer + description: The unique identifier of the project + project_name: + type: + - "null" + - string + description: The name of the project + to: + type: + - "null" + - string + description: The ending date of the expense record period + total_amount: + type: + - "null" + - number + description: The total amount of expenses incurred for the project + expenses_team: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable_amount: + type: + - "null" + - number + description: The amount that can be billed for the expense + currency: + type: + - "null" + - string + description: The currency in which the expense is incurred + from: + type: + - "null" + - string + description: The start date of the expense + is_contractor: + type: + - "null" + - boolean + description: Indicates if the user is a contractor + to: + type: + - "null" + - string + description: The end date of the expense + total_amount: + type: + - "null" + - number + description: The total amount of the expense + user_id: + type: + - "null" + - integer + description: The ID of the user associated with the expense + user_name: + type: + - "null" + - string + description: The name of the user associated with the expense + project_budget: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + budget: + type: + - "null" + - number + description: Total budget allocated for the project + budget_by: + type: + - "null" + - string + description: Person or entity responsible for the budget + budget_is_monthly: + type: + - "null" + - boolean + description: Indicates if the budget is calculated on a monthly basis + budget_remaining: + type: + - "null" + - number + description: Remaining budget amount available for the project + budget_spent: + type: + - "null" + - number + description: Total amount spent from the budget + client_id: + type: + - "null" + - integer + description: Unique identifier for the client associated with the project + client_name: + type: + - "null" + - string + description: Name of the client associated with the project + from: + type: + - "null" + - string + description: Start date of the budget period + is_active: + type: + - "null" + - boolean + description: Indicates if the project is currently active + project_id: + type: + - "null" + - integer + description: Unique identifier for the project + project_name: + type: + - "null" + - string + description: Name of the project + to: + type: + - "null" + - string + description: End date of the budget period + time_clients: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable_amount: + type: + - "null" + - number + description: >- + The amount that can be billed for the client's hours worked within the + specified timeframe. + billable_hours: + type: + - "null" + - number + description: >- + The total number of billable hours worked for the client within the + specified timeframe. + client_id: + type: + - "null" + - integer + description: The unique identifier of the client associated with the time entries. + client_name: + type: + - "null" + - string + description: The name of the client for whom the time entries were recorded. + currency: + type: + - "null" + - string + description: The currency used for billing the client's time entries. + from: + type: + - "null" + - string + description: >- + The start date and time of the timeframe for which the time entries + are being fetched. + to: + type: + - "null" + - string + description: >- + The end date and time of the timeframe for which the time entries are + being fetched. + total_hours: + type: + - "null" + - number + description: >- + The total number of hours worked for the client within the specified + timeframe, including both billable and non-billable hours. + time_projects: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable_amount: + type: + - "null" + - number + description: >- + The total amount that can be billed for this project in the given + currency. + billable_hours: + type: + - "null" + - number + description: The number of billable hours spent on this project. + client_id: + type: + - "null" + - integer + description: The unique identifier for the client associated with this project. + client_name: + type: + - "null" + - string + description: The name of the client associated with this project. + currency: + type: + - "null" + - string + description: The currency in which the billable amount is specified. + from: + type: + - "null" + - string + description: The start date for the project time frame. + project_id: + type: + - "null" + - integer + description: The unique identifier for the project. + project_name: + type: + - "null" + - string + description: The name of the project. + to: + type: + - "null" + - string + description: The end date for the project time frame. + total_hours: + type: + - "null" + - number + description: The total number of hours spent on this project. + time_tasks: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable_amount: + type: + - "null" + - number + description: The amount that can be billed for this time task + billable_hours: + type: + - "null" + - number + description: The number of hours that can be billed for this time task + currency: + type: + - "null" + - string + description: The currency in which the billable amount is calculated + from: + type: + - "null" + - string + description: The starting time of the time task + task_id: + type: + - "null" + - integer + description: The unique identifier for the task associated with this time entry + task_name: + type: + - "null" + - string + description: The name of the task associated with this time entry + to: + type: + - "null" + - string + description: The ending time of the time task + total_hours: + type: + - "null" + - number + description: The total number of hours spent on this time task + time_team: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + billable_amount: + type: + - "null" + - number + description: The amount that can be billed for the time period + billable_hours: + type: + - "null" + - number + description: The number of hours that can be billed for the time period + currency: + type: + - "null" + - string + description: The currency used for billing + from: + type: + - "null" + - string + description: The start date and time of the time period + is_contractor: + type: + - "null" + - boolean + description: Flag indicating if the user is a contractor + to: + type: + - "null" + - string + description: The end date and time of the time period + total_hours: + type: + - "null" + - number + description: The total number of hours worked for the time period + user_id: + type: + - "null" + - integer + description: The unique identifier of the user + user_name: + type: + - "null" + - string + description: The name of the user + uninvoiced: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + client_id: + type: + - "null" + - integer + description: Unique identifier for the client + client_name: + type: + - "null" + - string + description: Name of the client + currency: + type: + - "null" + - string + description: Currency used for the transaction + from: + type: + - "null" + - string + description: Start date for the data range + project_id: + type: + - "null" + - integer + description: Unique identifier for the project + project_name: + type: + - "null" + - string + description: Name of the project + to: + type: + - "null" + - string + description: End date for the data range + total_hours: + type: + - "null" + - number + description: Total hours tracked for the project within the data range + uninvoiced_amount: + type: + - "null" + - number + description: Total amount yet to be invoiced for the project within the data range + uninvoiced_expenses: + type: + - "null" + - number + description: >- + Total expenses yet to be invoiced for the project within the data + range + uninvoiced_hours: + type: + - "null" + - number + description: Total hours yet to be invoiced for the project within the data range + estimate_messages: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + body: + type: + - "null" + - string + description: The main content of the message. + created_at: + type: + - "null" + - string + description: The date and time when the message was created. + format: date-time + event_type: + type: + - "null" + - string + description: The type of event associated with the message. + id: + type: + - "null" + - integer + description: The unique identifier for the message. + parent_id: + type: integer + description: The identifier of the parent message, if this is a reply. + recipients: + type: + - "null" + - array + description: Details of the recipients of the message. + items: + type: object + properties: + email: + type: + - string + - "null" + description: The email address of a recipient. + name: + type: + - string + - "null" + description: The name of a recipient. + send_me_a_copy: + type: + - "null" + - boolean + description: Indicates if the sender requested a copy of the message. + sent_by: + type: + - "null" + - string + description: The name of the user who sent the message. + sent_by_email: + type: + - "null" + - string + description: The email address of the user who sent the message. + sent_from: + type: + - "null" + - string + description: The name displayed as the sender. + sent_from_email: + type: + - "null" + - string + description: The email address displayed as the sender. + subject: + type: + - "null" + - string + description: The subject or title of the message. + updated_at: + type: + - "null" + - string + description: The date and time when the message was last updated. + format: date-time + invoice_messages: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + attach_pdf: + type: + - "null" + - boolean + description: Indicates if a PDF file is attached to the message. + body: + type: + - "null" + - string + description: The content of the invoice message. + created_at: + type: + - "null" + - string + description: The date and time when the message was created. + format: date-time + event_type: + type: + - "null" + - string + description: The type of event associated with the message. + id: + type: + - "null" + - integer + description: The unique identifier of the invoice message. + include_link_to_client_invoice: + type: + - "null" + - boolean + description: Indicates if a link to the client invoice is included. + parent_id: + type: integer + description: The ID of the parent message if it's a reply or related message. + recipients: + type: + - "null" + - array + description: List of recipients for the message. + items: + type: object + properties: + email: + type: string + description: Email address of the recipient. + name: + type: string + description: Name of the recipient. + reminder: + type: + - "null" + - boolean + description: Indicates if the message is a reminder. + send_me_a_copy: + type: + - "null" + - boolean + description: Option to send a copy of the message to the sender. + send_reminder_on: + type: + - "null" + - string + description: The date to send a reminder for the message. + sent_by: + type: + - "null" + - string + description: The sender of the message. + sent_by_email: + type: + - "null" + - string + description: Email address of the sender. + sent_from: + type: + - "null" + - string + description: The display name of the sender. + sent_from_email: + type: + - "null" + - string + description: Email address used to send the message. + subject: + type: + - "null" + - string + description: The subject of the invoice message. + thank_you: + type: + - "null" + - boolean + description: Indicates if the message is a thank you message. + updated_at: + type: + - "null" + - string + description: The date and time when the message was last updated. + format: date-time + invoice_payments: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + amount: + type: + - "null" + - number + description: The amount of the invoice payment. + created_at: + type: + - "null" + - string + description: The timestamp when the invoice payment was created. + format: date-time + id: + type: + - "null" + - integer + description: The unique identifier of the invoice payment. + notes: + type: + - "null" + - string + description: Any additional notes or comments related to the invoice payment. + paid_at: + type: + - "null" + - string + description: The timestamp when the invoice payment was paid. + format: date-time + paid_date: + type: + - "null" + - string + description: The date when the invoice payment was paid. + format: date + parent_id: + type: integer + description: The ID of the parent invoice associated with this payment. + payment_gateway: + type: + - "null" + - object + description: Information about the payment gateway used for the transaction. + properties: + id: + type: + - "null" + - integer + description: The unique identifier of the payment gateway. + name: + type: + - "null" + - string + description: The name of the payment gateway. + recorded_by: + type: + - "null" + - string + description: The user who recorded this invoice payment. + recorded_by_email: + type: + - "null" + - string + description: The email address of the user who recorded this invoice payment. + transaction_id: + type: + - "null" + - string + description: The transaction ID associated with the invoice payment. + updated_at: + type: + - "null" + - string + description: The timestamp when the invoice payment was last updated. + format: date-time + project_assignments: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + budget: + type: + - "null" + - number + description: The budget allocated for this project assignment + client: + type: + - "null" + - object + description: Client information for the project assignment + properties: + currency: + type: + - "null" + - string + description: The currency used by the client + id: + type: + - "null" + - integer + description: The unique identifier of the client + name: + type: + - "null" + - string + description: The name of the client + created_at: + type: + - "null" + - string + description: The date and time when the project assignment was created + format: date-time + hourly_rate: + type: + - "null" + - number + description: The hourly rate for this project assignment + id: + type: + - "null" + - integer + description: The unique identifier of the project assignment + is_active: + type: + - "null" + - boolean + description: Indicates whether the project assignment is currently active + is_project_manager: + type: + - "null" + - boolean + description: Indicates whether the user is assigned as a project manager + parent_id: + type: integer + description: >- + The parent project assignment ID if this assignment is a + sub-assignment + project: + type: + - "null" + - object + description: Project information for the assignment + properties: + code: + type: + - "null" + - string + description: The code associated with the project + id: + type: + - "null" + - integer + description: The unique identifier of the project + name: + type: + - "null" + - string + description: The name of the project + task_assignments: + type: + - "null" + - array + description: List of task assignments for the project + items: + type: object + properties: + billable: + type: + - "null" + - boolean + description: Indicates whether the task is billable + budget: + type: + - "null" + - number + description: The budget allocated for this task assignment + created_at: + type: + - string + - "null" + description: The date and time when the task assignment was created + hourly_rate: + type: + - "null" + - number + description: The hourly rate for this task assignment + id: + type: + - "null" + - integer + description: The unique identifier of the task assignment + is_active: + type: + - "null" + - boolean + description: Indicates whether the task assignment is currently active + task: + type: + - object + - "null" + description: Information about a specific task assigned + properties: + id: + type: + - "null" + - integer + description: The unique identifier of the task + name: + type: + - "null" + - string + description: The name of the task + updated_at: + type: + - "null" + - string + description: The date and time when the task assignment was last updated + updated_at: + type: + - "null" + - string + description: The date and time when the project assignment was last updated + format: date-time + use_default_rates: + type: + - "null" + - boolean + description: Indicates whether default rates are used for this project assignment + billable_rates: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + amount: + type: + - "null" + - number + description: The billable amount associated with this rate. + created_at: + type: + - "null" + - string + description: The date and time when this rate was created. + format: date-time + end_date: + type: + - "null" + - string + description: The end date for this billable rate period. + format: date + id: + type: + - "null" + - integer + description: The unique identifier for this billable rate. + parent_id: + type: integer + description: The identifier of the parent resource associated with this rate. + start_date: + type: + - "null" + - string + description: The start date for this billable rate period. + format: date + updated_at: + type: + - "null" + - string + description: The date and time when this rate was last updated. + format: date-time + cost_rates: + type: object + $schema: http://json-schema.org/draft-07/schema# + additionalProperties: true + properties: + amount: + type: + - "null" + - number + description: The cost rate amount associated with this data entry. + created_at: + type: + - "null" + - string + description: The timestamp indicating when this cost rate entry was created. + format: date-time + end_date: + type: + - "null" + - string + description: >- + The end date for which the cost rate is valid. Only applicable for + intervals. + format: date + id: + type: + - "null" + - integer + description: The unique identifier for this cost rate entry. + parent_id: + type: integer + description: The parent identifier if this cost rate is a child entry. + start_date: + type: + - "null" + - string + description: >- + The start date from which the cost rate is valid. Only applicable for + intervals. + format: date + updated_at: + type: + - "null" + - string + description: The timestamp for the last update made to this cost rate entry. + format: date-time diff --git a/airbyte-integrations/connectors/source-harvest/metadata.yaml b/airbyte-integrations/connectors/source-harvest/metadata.yaml index 72d6e7798ec3..06783b4dcf9a 100644 --- a/airbyte-integrations/connectors/source-harvest/metadata.yaml +++ b/airbyte-integrations/connectors/source-harvest/metadata.yaml @@ -6,11 +6,11 @@ data: hosts: - api.harvestapp.com connectorBuildOptions: - baseImage: docker.io/airbyte/python-connector-base:2.0.0@sha256:c44839ba84406116e8ba68722a0f30e8f6e7056c726f447681bb9e9ece8bd916 + baseImage: docker.io/airbyte/source-declarative-manifest:5.11.1@sha256:f48a7ddc1f3acecbd8eb6a10a3146e8d0396e9a4dede77beafb76924f416df65 connectorSubtype: api connectorType: source definitionId: fe2b4084-3386-4d3b-9ad6-308f61a6f1e6 - dockerImageTag: 1.0.19 + dockerImageTag: 1.1.0-rc1 dockerRepository: airbyte/source-harvest documentationUrl: https://docs.airbyte.com/integrations/sources/harvest githubIssueLabel: source-harvest @@ -20,7 +20,7 @@ data: name: Harvest remoteRegistries: pypi: - enabled: true + enabled: false packageName: airbyte-source-harvest registryOverrides: cloud: @@ -28,6 +28,7 @@ data: oss: enabled: true releases: + isReleaseCandidate: true breakingChanges: 1.0.0: message: @@ -59,7 +60,7 @@ data: releaseStage: generally_available supportLevel: certified tags: - - language:python + - language:manifest-only - cdk:low-code connectorTestSuitesOptions: - suite: liveTests diff --git a/airbyte-integrations/connectors/source-harvest/poetry.lock b/airbyte-integrations/connectors/source-harvest/poetry.lock deleted file mode 100644 index f0717e4a151c..000000000000 --- a/airbyte-integrations/connectors/source-harvest/poetry.lock +++ /dev/null @@ -1,1063 +0,0 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. - -[[package]] -name = "airbyte-cdk" -version = "0.80.0" -description = "A framework for writing Airbyte Connectors." -optional = false -python-versions = "<4.0,>=3.9" -files = [ - {file = "airbyte_cdk-0.80.0-py3-none-any.whl", hash = "sha256:060e92323a73674fa4e9e2e4a1eb312b9b9d072c9bbe5fa28f54ef21cb4974f3"}, - {file = "airbyte_cdk-0.80.0.tar.gz", hash = "sha256:1383512a83917fecca5b24cea4c72aa5c561cf96dd464485fbcefda48fe574c5"}, -] - -[package.dependencies] -airbyte-protocol-models = "0.5.1" -backoff = "*" -cachetools = "*" -Deprecated = ">=1.2,<1.3" -dpath = ">=2.0.1,<2.1.0" -genson = "1.2.2" -isodate = ">=0.6.1,<0.7.0" -Jinja2 = ">=3.1.2,<3.2.0" -jsonref = ">=0.2,<0.3" -jsonschema = ">=3.2.0,<3.3.0" -pendulum = "<3.0.0" -pydantic = ">=1.10.8,<2.0.0" -pyrate-limiter = ">=3.1.0,<3.2.0" -python-dateutil = "*" -PyYAML = ">=6.0.1,<7.0.0" -requests = "*" -requests_cache = "*" -wcmatch = "8.4" - -[package.extras] -file-based = ["avro (>=1.11.2,<1.12.0)", "fastavro (>=1.8.0,<1.9.0)", "markdown", "pdf2image (==1.16.3)", "pdfminer.six (==20221105)", "pyarrow (>=15.0.0,<15.1.0)", "pytesseract (==0.3.10)", "unstructured.pytesseract (>=0.3.12)", "unstructured[docx,pptx] (==0.10.27)"] -sphinx-docs = ["Sphinx (>=4.2,<4.3)", "sphinx-rtd-theme (>=1.0,<1.1)"] -vector-db-based = ["cohere (==4.21)", "langchain (==0.0.271)", "openai[embeddings] (==0.27.9)", "tiktoken (==0.4.0)"] - -[[package]] -name = "airbyte-protocol-models" -version = "0.5.1" -description = "Declares the Airbyte Protocol." -optional = false -python-versions = ">=3.8" -files = [ - {file = "airbyte_protocol_models-0.5.1-py3-none-any.whl", hash = "sha256:dfe84e130e51ce2ae81a06d5aa36f6c5ce3152b9e36e6f0195fad6c3dab0927e"}, - {file = "airbyte_protocol_models-0.5.1.tar.gz", hash = "sha256:7c8b16c7c1c7956b1996052e40585a3a93b1e44cb509c4e97c1ee4fe507ea086"}, -] - -[package.dependencies] -pydantic = ">=1.9.2,<2.0.0" - -[[package]] -name = "atomicwrites" -version = "1.4.1" -description = "Atomic file writes." -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, -] - -[[package]] -name = "attrs" -version = "24.2.0" -description = "Classes Without Boilerplate" -optional = false -python-versions = ">=3.7" -files = [ - {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, - {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, -] - -[package.extras] -benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] - -[[package]] -name = "backoff" -version = "2.2.1" -description = "Function decoration for backoff and retry" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, - {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, -] - -[[package]] -name = "bracex" -version = "2.5.post1" -description = "Bash style brace expander." -optional = false -python-versions = ">=3.8" -files = [ - {file = "bracex-2.5.post1-py3-none-any.whl", hash = "sha256:13e5732fec27828d6af308628285ad358047cec36801598368cb28bc631dbaf6"}, - {file = "bracex-2.5.post1.tar.gz", hash = "sha256:12c50952415bfa773d2d9ccb8e79651b8cdb1f31a42f6091b804f6ba2b4a66b6"}, -] - -[[package]] -name = "cachetools" -version = "5.5.0" -description = "Extensible memoizing collections and decorators" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, - {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, -] - -[[package]] -name = "cattrs" -version = "24.1.2" -description = "Composable complex class support for attrs and dataclasses." -optional = false -python-versions = ">=3.8" -files = [ - {file = "cattrs-24.1.2-py3-none-any.whl", hash = "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0"}, - {file = "cattrs-24.1.2.tar.gz", hash = "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85"}, -] - -[package.dependencies] -attrs = ">=23.1.0" -exceptiongroup = {version = ">=1.1.1", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.1.0,<4.6.3 || >4.6.3", markers = "python_version < \"3.11\""} - -[package.extras] -bson = ["pymongo (>=4.4.0)"] -cbor2 = ["cbor2 (>=5.4.6)"] -msgpack = ["msgpack (>=1.0.5)"] -msgspec = ["msgspec (>=0.18.5)"] -orjson = ["orjson (>=3.9.2)"] -pyyaml = ["pyyaml (>=6.0)"] -tomlkit = ["tomlkit (>=0.11.8)"] -ujson = ["ujson (>=5.7.0)"] - -[[package]] -name = "certifi" -version = "2024.8.30" -description = "Python package for providing Mozilla's CA Bundle." -optional = false -python-versions = ">=3.6" -files = [ - {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, - {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, -] - -[[package]] -name = "charset-normalizer" -version = "3.3.2" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, -] - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "deprecated" -version = "1.2.14" -description = "Python @deprecated decorator to deprecate old python classes, functions or methods." -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, - {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, -] - -[package.dependencies] -wrapt = ">=1.10,<2" - -[package.extras] -dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] - -[[package]] -name = "dpath" -version = "2.0.8" -description = "Filesystem-like pathing and searching for dictionaries" -optional = false -python-versions = ">=3.7" -files = [ - {file = "dpath-2.0.8-py3-none-any.whl", hash = "sha256:f92f595214dd93a00558d75d4b858beee519f4cffca87f02616ad6cd013f3436"}, - {file = "dpath-2.0.8.tar.gz", hash = "sha256:a3440157ebe80d0a3ad794f1b61c571bef125214800ffdb9afc9424e8250fe9b"}, -] - -[[package]] -name = "exceptiongroup" -version = "1.2.2" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, -] - -[package.extras] -test = ["pytest (>=6)"] - -[[package]] -name = "freezegun" -version = "1.5.1" -description = "Let your Python tests travel through time" -optional = false -python-versions = ">=3.7" -files = [ - {file = "freezegun-1.5.1-py3-none-any.whl", hash = "sha256:bf111d7138a8abe55ab48a71755673dbaa4ab87f4cff5634a4442dfec34c15f1"}, - {file = "freezegun-1.5.1.tar.gz", hash = "sha256:b29dedfcda6d5e8e083ce71b2b542753ad48cfec44037b3fc79702e2980a89e9"}, -] - -[package.dependencies] -python-dateutil = ">=2.7" - -[[package]] -name = "genson" -version = "1.2.2" -description = "GenSON is a powerful, user-friendly JSON Schema generator." -optional = false -python-versions = "*" -files = [ - {file = "genson-1.2.2.tar.gz", hash = "sha256:8caf69aa10af7aee0e1a1351d1d06801f4696e005f06cedef438635384346a16"}, -] - -[[package]] -name = "idna" -version = "3.10" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.6" -files = [ - {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, - {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, -] - -[package.extras] -all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - -[[package]] -name = "isodate" -version = "0.6.1" -description = "An ISO 8601 date/time/duration parser and formatter" -optional = false -python-versions = "*" -files = [ - {file = "isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"}, - {file = "isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"}, -] - -[package.dependencies] -six = "*" - -[[package]] -name = "jinja2" -version = "3.1.4" -description = "A very fast and expressive template engine." -optional = false -python-versions = ">=3.7" -files = [ - {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, - {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, -] - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "jsonref" -version = "0.2" -description = "An implementation of JSON Reference for Python" -optional = false -python-versions = "*" -files = [ - {file = "jsonref-0.2-py3-none-any.whl", hash = "sha256:b1e82fa0b62e2c2796a13e5401fe51790b248f6d9bf9d7212a3e31a3501b291f"}, - {file = "jsonref-0.2.tar.gz", hash = "sha256:f3c45b121cf6257eafabdc3a8008763aed1cd7da06dbabc59a9e4d2a5e4e6697"}, -] - -[[package]] -name = "jsonschema" -version = "3.2.0" -description = "An implementation of JSON Schema validation for Python" -optional = false -python-versions = "*" -files = [ - {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, - {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, -] - -[package.dependencies] -attrs = ">=17.4.0" -pyrsistent = ">=0.14.0" -setuptools = "*" -six = ">=1.11.0" - -[package.extras] -format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"] -format-nongpl = ["idna", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "webcolors"] - -[[package]] -name = "markupsafe" -version = "2.1.5" -description = "Safely add untrusted strings to HTML/XML markup." -optional = false -python-versions = ">=3.7" -files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, -] - -[[package]] -name = "packaging" -version = "24.1" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, -] - -[[package]] -name = "pendulum" -version = "2.1.2" -description = "Python datetimes made easy" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "pendulum-2.1.2-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:b6c352f4bd32dff1ea7066bd31ad0f71f8d8100b9ff709fb343f3b86cee43efe"}, - {file = "pendulum-2.1.2-cp27-cp27m-win_amd64.whl", hash = "sha256:318f72f62e8e23cd6660dbafe1e346950281a9aed144b5c596b2ddabc1d19739"}, - {file = "pendulum-2.1.2-cp35-cp35m-macosx_10_15_x86_64.whl", hash = "sha256:0731f0c661a3cb779d398803655494893c9f581f6488048b3fb629c2342b5394"}, - {file = "pendulum-2.1.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:3481fad1dc3f6f6738bd575a951d3c15d4b4ce7c82dce37cf8ac1483fde6e8b0"}, - {file = "pendulum-2.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9702069c694306297ed362ce7e3c1ef8404ac8ede39f9b28b7c1a7ad8c3959e3"}, - {file = "pendulum-2.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:fb53ffa0085002ddd43b6ca61a7b34f2d4d7c3ed66f931fe599e1a531b42af9b"}, - {file = "pendulum-2.1.2-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:c501749fdd3d6f9e726086bf0cd4437281ed47e7bca132ddb522f86a1645d360"}, - {file = "pendulum-2.1.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c807a578a532eeb226150d5006f156632df2cc8c5693d778324b43ff8c515dd0"}, - {file = "pendulum-2.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2d1619a721df661e506eff8db8614016f0720ac171fe80dda1333ee44e684087"}, - {file = "pendulum-2.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f888f2d2909a414680a29ae74d0592758f2b9fcdee3549887779cd4055e975db"}, - {file = "pendulum-2.1.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e95d329384717c7bf627bf27e204bc3b15c8238fa8d9d9781d93712776c14002"}, - {file = "pendulum-2.1.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4c9c689747f39d0d02a9f94fcee737b34a5773803a64a5fdb046ee9cac7442c5"}, - {file = "pendulum-2.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1245cd0075a3c6d889f581f6325dd8404aca5884dea7223a5566c38aab94642b"}, - {file = "pendulum-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:db0a40d8bcd27b4fb46676e8eb3c732c67a5a5e6bfab8927028224fbced0b40b"}, - {file = "pendulum-2.1.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f5e236e7730cab1644e1b87aca3d2ff3e375a608542e90fe25685dae46310116"}, - {file = "pendulum-2.1.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:de42ea3e2943171a9e95141f2eecf972480636e8e484ccffaf1e833929e9e052"}, - {file = "pendulum-2.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7c5ec650cb4bec4c63a89a0242cc8c3cebcec92fcfe937c417ba18277d8560be"}, - {file = "pendulum-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:33fb61601083f3eb1d15edeb45274f73c63b3c44a8524703dc143f4212bf3269"}, - {file = "pendulum-2.1.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:29c40a6f2942376185728c9a0347d7c0f07905638c83007e1d262781f1e6953a"}, - {file = "pendulum-2.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:94b1fc947bfe38579b28e1cccb36f7e28a15e841f30384b5ad6c5e31055c85d7"}, - {file = "pendulum-2.1.2.tar.gz", hash = "sha256:b06a0ca1bfe41c990bbf0c029f0b6501a7f2ec4e38bfec730712015e8860f207"}, -] - -[package.dependencies] -python-dateutil = ">=2.6,<3.0" -pytzdata = ">=2020.1" - -[[package]] -name = "platformdirs" -version = "4.3.6" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.8" -files = [ - {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, - {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, -] - -[package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.11.2)"] - -[[package]] -name = "pluggy" -version = "1.5.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] - -[[package]] -name = "pydantic" -version = "1.10.18" -description = "Data validation and settings management using python type hints" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pydantic-1.10.18-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e405ffcc1254d76bb0e760db101ee8916b620893e6edfbfee563b3c6f7a67c02"}, - {file = "pydantic-1.10.18-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e306e280ebebc65040034bff1a0a81fd86b2f4f05daac0131f29541cafd80b80"}, - {file = "pydantic-1.10.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11d9d9b87b50338b1b7de4ebf34fd29fdb0d219dc07ade29effc74d3d2609c62"}, - {file = "pydantic-1.10.18-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b661ce52c7b5e5f600c0c3c5839e71918346af2ef20062705ae76b5c16914cab"}, - {file = "pydantic-1.10.18-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c20f682defc9ef81cd7eaa485879ab29a86a0ba58acf669a78ed868e72bb89e0"}, - {file = "pydantic-1.10.18-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c5ae6b7c8483b1e0bf59e5f1843e4fd8fd405e11df7de217ee65b98eb5462861"}, - {file = "pydantic-1.10.18-cp310-cp310-win_amd64.whl", hash = "sha256:74fe19dda960b193b0eb82c1f4d2c8e5e26918d9cda858cbf3f41dd28549cb70"}, - {file = "pydantic-1.10.18-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:72fa46abace0a7743cc697dbb830a41ee84c9db8456e8d77a46d79b537efd7ec"}, - {file = "pydantic-1.10.18-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef0fe7ad7cbdb5f372463d42e6ed4ca9c443a52ce544472d8842a0576d830da5"}, - {file = "pydantic-1.10.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a00e63104346145389b8e8f500bc6a241e729feaf0559b88b8aa513dd2065481"}, - {file = "pydantic-1.10.18-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae6fa2008e1443c46b7b3a5eb03800121868d5ab6bc7cda20b5df3e133cde8b3"}, - {file = "pydantic-1.10.18-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9f463abafdc92635da4b38807f5b9972276be7c8c5121989768549fceb8d2588"}, - {file = "pydantic-1.10.18-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3445426da503c7e40baccefb2b2989a0c5ce6b163679dd75f55493b460f05a8f"}, - {file = "pydantic-1.10.18-cp311-cp311-win_amd64.whl", hash = "sha256:467a14ee2183bc9c902579bb2f04c3d3dac00eff52e252850509a562255b2a33"}, - {file = "pydantic-1.10.18-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:efbc8a7f9cb5fe26122acba1852d8dcd1e125e723727c59dcd244da7bdaa54f2"}, - {file = "pydantic-1.10.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24a4a159d0f7a8e26bf6463b0d3d60871d6a52eac5bb6a07a7df85c806f4c048"}, - {file = "pydantic-1.10.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b74be007703547dc52e3c37344d130a7bfacca7df112a9e5ceeb840a9ce195c7"}, - {file = "pydantic-1.10.18-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcb20d4cb355195c75000a49bb4a31d75e4295200df620f454bbc6bdf60ca890"}, - {file = "pydantic-1.10.18-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:46f379b8cb8a3585e3f61bf9ae7d606c70d133943f339d38b76e041ec234953f"}, - {file = "pydantic-1.10.18-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cbfbca662ed3729204090c4d09ee4beeecc1a7ecba5a159a94b5a4eb24e3759a"}, - {file = "pydantic-1.10.18-cp312-cp312-win_amd64.whl", hash = "sha256:c6d0a9f9eccaf7f438671a64acf654ef0d045466e63f9f68a579e2383b63f357"}, - {file = "pydantic-1.10.18-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3d5492dbf953d7d849751917e3b2433fb26010d977aa7a0765c37425a4026ff1"}, - {file = "pydantic-1.10.18-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe734914977eed33033b70bfc097e1baaffb589517863955430bf2e0846ac30f"}, - {file = "pydantic-1.10.18-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15fdbe568beaca9aacfccd5ceadfb5f1a235087a127e8af5e48df9d8a45ae85c"}, - {file = "pydantic-1.10.18-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c3e742f62198c9eb9201781fbebe64533a3bbf6a76a91b8d438d62b813079dbc"}, - {file = "pydantic-1.10.18-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19a3bd00b9dafc2cd7250d94d5b578edf7a0bd7daf102617153ff9a8fa37871c"}, - {file = "pydantic-1.10.18-cp37-cp37m-win_amd64.whl", hash = "sha256:2ce3fcf75b2bae99aa31bd4968de0474ebe8c8258a0110903478bd83dfee4e3b"}, - {file = "pydantic-1.10.18-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:335a32d72c51a313b33fa3a9b0fe283503272ef6467910338e123f90925f0f03"}, - {file = "pydantic-1.10.18-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:34a3613c7edb8c6fa578e58e9abe3c0f5e7430e0fc34a65a415a1683b9c32d9a"}, - {file = "pydantic-1.10.18-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9ee4e6ca1d9616797fa2e9c0bfb8815912c7d67aca96f77428e316741082a1b"}, - {file = "pydantic-1.10.18-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23e8ec1ce4e57b4f441fc91e3c12adba023fedd06868445a5b5f1d48f0ab3682"}, - {file = "pydantic-1.10.18-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:44ae8a3e35a54d2e8fa88ed65e1b08967a9ef8c320819a969bfa09ce5528fafe"}, - {file = "pydantic-1.10.18-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5389eb3b48a72da28c6e061a247ab224381435256eb541e175798483368fdd3"}, - {file = "pydantic-1.10.18-cp38-cp38-win_amd64.whl", hash = "sha256:069b9c9fc645474d5ea3653788b544a9e0ccd3dca3ad8c900c4c6eac844b4620"}, - {file = "pydantic-1.10.18-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80b982d42515632eb51f60fa1d217dfe0729f008e81a82d1544cc392e0a50ddf"}, - {file = "pydantic-1.10.18-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aad8771ec8dbf9139b01b56f66386537c6fe4e76c8f7a47c10261b69ad25c2c9"}, - {file = "pydantic-1.10.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941a2eb0a1509bd7f31e355912eb33b698eb0051730b2eaf9e70e2e1589cae1d"}, - {file = "pydantic-1.10.18-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65f7361a09b07915a98efd17fdec23103307a54db2000bb92095457ca758d485"}, - {file = "pydantic-1.10.18-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6951f3f47cb5ca4da536ab161ac0163cab31417d20c54c6de5ddcab8bc813c3f"}, - {file = "pydantic-1.10.18-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7a4c5eec138a9b52c67f664c7d51d4c7234c5ad65dd8aacd919fb47445a62c86"}, - {file = "pydantic-1.10.18-cp39-cp39-win_amd64.whl", hash = "sha256:49e26c51ca854286bffc22b69787a8d4063a62bf7d83dc21d44d2ff426108518"}, - {file = "pydantic-1.10.18-py3-none-any.whl", hash = "sha256:06a189b81ffc52746ec9c8c007f16e5167c8b0a696e1a726369327e3db7b2a82"}, - {file = "pydantic-1.10.18.tar.gz", hash = "sha256:baebdff1907d1d96a139c25136a9bb7d17e118f133a76a2ef3b845e831e3403a"}, -] - -[package.dependencies] -typing-extensions = ">=4.2.0" - -[package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] - -[[package]] -name = "pyrate-limiter" -version = "3.1.1" -description = "Python Rate-Limiter using Leaky-Bucket Algorithm" -optional = false -python-versions = ">=3.8,<4.0" -files = [ - {file = "pyrate_limiter-3.1.1-py3-none-any.whl", hash = "sha256:c51906f1d51d56dc992ff6c26e8300e32151bc6cfa3e6559792e31971dfd4e2b"}, - {file = "pyrate_limiter-3.1.1.tar.gz", hash = "sha256:2f57eda712687e6eccddf6afe8f8a15b409b97ed675fe64a626058f12863b7b7"}, -] - -[package.extras] -all = ["filelock (>=3.0)", "redis (>=5.0.0,<6.0.0)"] -docs = ["furo (>=2022.3.4,<2023.0.0)", "myst-parser (>=0.17)", "sphinx (>=4.3.0,<5.0.0)", "sphinx-autodoc-typehints (>=1.17,<2.0)", "sphinx-copybutton (>=0.5)", "sphinxcontrib-apidoc (>=0.3,<0.4)"] - -[[package]] -name = "pyrsistent" -version = "0.20.0" -description = "Persistent/Functional/Immutable data structures" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pyrsistent-0.20.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce"}, - {file = "pyrsistent-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f"}, - {file = "pyrsistent-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34"}, - {file = "pyrsistent-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b"}, - {file = "pyrsistent-0.20.0-cp310-cp310-win32.whl", hash = "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f"}, - {file = "pyrsistent-0.20.0-cp310-cp310-win_amd64.whl", hash = "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7"}, - {file = "pyrsistent-0.20.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958"}, - {file = "pyrsistent-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8"}, - {file = "pyrsistent-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a"}, - {file = "pyrsistent-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224"}, - {file = "pyrsistent-0.20.0-cp311-cp311-win32.whl", hash = "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656"}, - {file = "pyrsistent-0.20.0-cp311-cp311-win_amd64.whl", hash = "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee"}, - {file = "pyrsistent-0.20.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e"}, - {file = "pyrsistent-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e"}, - {file = "pyrsistent-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3"}, - {file = "pyrsistent-0.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d"}, - {file = "pyrsistent-0.20.0-cp312-cp312-win32.whl", hash = "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174"}, - {file = "pyrsistent-0.20.0-cp312-cp312-win_amd64.whl", hash = "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d"}, - {file = "pyrsistent-0.20.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:79ed12ba79935adaac1664fd7e0e585a22caa539dfc9b7c7c6d5ebf91fb89054"}, - {file = "pyrsistent-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f920385a11207dc372a028b3f1e1038bb244b3ec38d448e6d8e43c6b3ba20e98"}, - {file = "pyrsistent-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f5c2d012671b7391803263419e31b5c7c21e7c95c8760d7fc35602353dee714"}, - {file = "pyrsistent-0.20.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef3992833fbd686ee783590639f4b8343a57f1f75de8633749d984dc0eb16c86"}, - {file = "pyrsistent-0.20.0-cp38-cp38-win32.whl", hash = "sha256:881bbea27bbd32d37eb24dd320a5e745a2a5b092a17f6debc1349252fac85423"}, - {file = "pyrsistent-0.20.0-cp38-cp38-win_amd64.whl", hash = "sha256:6d270ec9dd33cdb13f4d62c95c1a5a50e6b7cdd86302b494217137f760495b9d"}, - {file = "pyrsistent-0.20.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ca52d1ceae015859d16aded12584c59eb3825f7b50c6cfd621d4231a6cc624ce"}, - {file = "pyrsistent-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b318ca24db0f0518630e8b6f3831e9cba78f099ed5c1d65ffe3e023003043ba0"}, - {file = "pyrsistent-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed2c3216a605dc9a6ea50c7e84c82906e3684c4e80d2908208f662a6cbf9022"}, - {file = "pyrsistent-0.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e14c95c16211d166f59c6611533d0dacce2e25de0f76e4c140fde250997b3ca"}, - {file = "pyrsistent-0.20.0-cp39-cp39-win32.whl", hash = "sha256:f058a615031eea4ef94ead6456f5ec2026c19fb5bd6bfe86e9665c4158cf802f"}, - {file = "pyrsistent-0.20.0-cp39-cp39-win_amd64.whl", hash = "sha256:58b8f6366e152092194ae68fefe18b9f0b4f89227dfd86a07770c3d86097aebf"}, - {file = "pyrsistent-0.20.0-py3-none-any.whl", hash = "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b"}, - {file = "pyrsistent-0.20.0.tar.gz", hash = "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4"}, -] - -[[package]] -name = "pytest" -version = "6.2.5" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, - {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, -] - -[package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} -attrs = ">=19.2.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -toml = "*" - -[package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] - -[[package]] -name = "pytest-mock" -version = "3.14.0" -description = "Thin-wrapper around the mock package for easier use with pytest" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, - {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, -] - -[package.dependencies] -pytest = ">=6.2.5" - -[package.extras] -dev = ["pre-commit", "pytest-asyncio", "tox"] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -files = [ - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "pytzdata" -version = "2020.1" -description = "The Olson timezone database for Python." -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "pytzdata-2020.1-py2.py3-none-any.whl", hash = "sha256:e1e14750bcf95016381e4d472bad004eef710f2d6417240904070b3d6654485f"}, - {file = "pytzdata-2020.1.tar.gz", hash = "sha256:3efa13b335a00a8de1d345ae41ec78dd11c9f8807f522d39850f2dd828681540"}, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, - {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, - {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, - {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, - {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, - {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, - {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, - {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, - {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, - {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, - {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, - {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, - {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, - {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, - {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, - {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, - {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, -] - -[[package]] -name = "requests" -version = "2.32.3" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.8" -files = [ - {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, - {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "requests-cache" -version = "1.2.1" -description = "A persistent cache for python requests" -optional = false -python-versions = ">=3.8" -files = [ - {file = "requests_cache-1.2.1-py3-none-any.whl", hash = "sha256:1285151cddf5331067baa82598afe2d47c7495a1334bfe7a7d329b43e9fd3603"}, - {file = "requests_cache-1.2.1.tar.gz", hash = "sha256:68abc986fdc5b8d0911318fbb5f7c80eebcd4d01bfacc6685ecf8876052511d1"}, -] - -[package.dependencies] -attrs = ">=21.2" -cattrs = ">=22.2" -platformdirs = ">=2.5" -requests = ">=2.22" -url-normalize = ">=1.4" -urllib3 = ">=1.25.5" - -[package.extras] -all = ["boto3 (>=1.15)", "botocore (>=1.18)", "itsdangerous (>=2.0)", "pymongo (>=3)", "pyyaml (>=6.0.1)", "redis (>=3)", "ujson (>=5.4)"] -bson = ["bson (>=0.5)"] -docs = ["furo (>=2023.3,<2024.0)", "linkify-it-py (>=2.0,<3.0)", "myst-parser (>=1.0,<2.0)", "sphinx (>=5.0.2,<6.0.0)", "sphinx-autodoc-typehints (>=1.19)", "sphinx-automodapi (>=0.14)", "sphinx-copybutton (>=0.5)", "sphinx-design (>=0.2)", "sphinx-notfound-page (>=0.8)", "sphinxcontrib-apidoc (>=0.3)", "sphinxext-opengraph (>=0.9)"] -dynamodb = ["boto3 (>=1.15)", "botocore (>=1.18)"] -json = ["ujson (>=5.4)"] -mongodb = ["pymongo (>=3)"] -redis = ["redis (>=3)"] -security = ["itsdangerous (>=2.0)"] -yaml = ["pyyaml (>=6.0.1)"] - -[[package]] -name = "requests-mock" -version = "1.12.1" -description = "Mock out responses from the requests package" -optional = false -python-versions = ">=3.5" -files = [ - {file = "requests-mock-1.12.1.tar.gz", hash = "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401"}, - {file = "requests_mock-1.12.1-py2.py3-none-any.whl", hash = "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563"}, -] - -[package.dependencies] -requests = ">=2.22,<3" - -[package.extras] -fixture = ["fixtures"] - -[[package]] -name = "setuptools" -version = "75.1.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-75.1.0-py3-none-any.whl", hash = "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2"}, - {file = "setuptools-75.1.0.tar.gz", hash = "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538"}, -] - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] - -[[package]] -name = "typing-extensions" -version = "4.12.2" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, -] - -[[package]] -name = "url-normalize" -version = "1.4.3" -description = "URL normalization for Python" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" -files = [ - {file = "url-normalize-1.4.3.tar.gz", hash = "sha256:d23d3a070ac52a67b83a1c59a0e68f8608d1cd538783b401bc9de2c0fac999b2"}, - {file = "url_normalize-1.4.3-py2.py3-none-any.whl", hash = "sha256:ec3c301f04e5bb676d333a7fa162fa977ad2ca04b7e652bfc9fac4e405728eed"}, -] - -[package.dependencies] -six = "*" - -[[package]] -name = "urllib3" -version = "2.2.3" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.8" -files = [ - {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, - {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, -] - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "wcmatch" -version = "8.4" -description = "Wildcard/glob file name matcher." -optional = false -python-versions = ">=3.7" -files = [ - {file = "wcmatch-8.4-py3-none-any.whl", hash = "sha256:dc7351e5a7f8bbf4c6828d51ad20c1770113f5f3fd3dfe2a03cfde2a63f03f98"}, - {file = "wcmatch-8.4.tar.gz", hash = "sha256:ba4fc5558f8946bf1ffc7034b05b814d825d694112499c86035e0e4d398b6a67"}, -] - -[package.dependencies] -bracex = ">=2.1.1" - -[[package]] -name = "wrapt" -version = "1.16.0" -description = "Module for decorators, wrappers and monkey patching." -optional = false -python-versions = ">=3.6" -files = [ - {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, - {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, - {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, - {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, - {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, - {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, - {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, - {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, - {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, - {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, - {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, - {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, - {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, - {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, - {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, - {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, - {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, - {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, -] - -[metadata] -lock-version = "2.0" -python-versions = "^3.9,<3.12" -content-hash = "2aff7d489ba30abc8f6f649eb51145ab20ab4b4bd2e03657640a451ee40d2a99" diff --git a/airbyte-integrations/connectors/source-harvest/pyproject.toml b/airbyte-integrations/connectors/source-harvest/pyproject.toml deleted file mode 100644 index 28961b36adc0..000000000000 --- a/airbyte-integrations/connectors/source-harvest/pyproject.toml +++ /dev/null @@ -1,29 +0,0 @@ -[build-system] -requires = [ "poetry-core>=1.0.0",] -build-backend = "poetry.core.masonry.api" - -[tool.poetry] -version = "1.0.19" -name = "source-harvest" -description = "Source implementation for Harvest." -authors = [ "Airbyte ",] -license = "MIT" -readme = "README.md" -documentation = "https://docs.airbyte.com/integrations/sources/harvest" -homepage = "https://airbyte.com" -repository = "https://github.com/airbytehq/airbyte" -[[tool.poetry.packages]] -include = "source_harvest" - -[tool.poetry.dependencies] -python = "^3.9,<3.12" -airbyte-cdk = "0.80.0" - -[tool.poetry.scripts] -source-harvest = "source_harvest.run:run" - -[tool.poetry.group.dev.dependencies] -requests-mock = "^1.11.0" -pytest-mock = "^3.6.1" -pytest = "^6.1" -freezegun = "^1.4.0" diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/__init__.py b/airbyte-integrations/connectors/source-harvest/source_harvest/__init__.py deleted file mode 100644 index 0558fdc23880..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -MIT License - -Copyright (c) 2020 Airbyte - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -""" - -from .source import SourceHarvest - -__all__ = ["SourceHarvest"] diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/config_migrations.py b/airbyte-integrations/connectors/source-harvest/source_harvest/config_migrations.py deleted file mode 100644 index 3d7d22a2eb10..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/config_migrations.py +++ /dev/null @@ -1,104 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - - -import logging -from typing import Any, List, Mapping - -from airbyte_cdk.config_observation import create_connector_config_control_message -from airbyte_cdk.entrypoint import AirbyteEntrypoint -from airbyte_cdk.sources import Source -from airbyte_cdk.sources.message import InMemoryMessageRepository, MessageRepository - -logger = logging.getLogger("airbyte_logger") - - -class MigrateAuthType: - """ - This class stands for migrating the config at runtime. - This migration is backwards compatible with the previous version, as new `auth_type` property will be created and populated. - When falling back to the previous source version connector will not require the `auth_type` field. - """ - - message_repository: MessageRepository = InMemoryMessageRepository() - - @classmethod - def should_migrate(cls, config: Mapping[str, Any]) -> bool: - """ - Determines if a configuration requires migration. - - Args: - - config (Mapping[str, Any]): The configuration data to check. - - Returns: - - True: If the configuration requires migration (i.e. "auth_type" does not exist in the credentials being read). - - False: Otherwise. - """ - return "auth_type" not in config["credentials"] - - @classmethod - def set_auth_type(cls, config: Mapping[str, Any], source: Source = None) -> Mapping[str, Any]: - """ - Sets `auth_type` to "Token" if api_token exists in the credentials, sets it to "Client" for when client_id exists. Otherwise does not set `auth_type` as user has not provided any credentials. - - Args: - - config (Mapping[str, Any]): The configuration from which the `auth_type` should be added and set. - - source (Source, optional): The data source. Defaults to None. - - Returns: - - Mapping[str, Any]: The configuration after removing the key. - """ - if "api_token" in config["credentials"]: - config["credentials"]["auth_type"] = "Token" - elif "client_id" in config["credentials"]: - config["credentials"]["auth_type"] = "Client" - return config - - @classmethod - def modify_and_save(cls, config_path: str, source: Source, config: Mapping[str, Any]) -> Mapping[str, Any]: - """ - Modifies the configuration and then saves it back to the source. - - Args: - - config_path (str): The path where the configuration is stored. - - source (Source): The data source. - - config (Mapping[str, Any]): The current configuration. - - Returns: - - Mapping[str, Any]: The updated configuration. - """ - migrated_config = cls.set_auth_type(config, source) - source.write_config(migrated_config, config_path) - return migrated_config - - @classmethod - def emit_control_message(cls, migrated_config: Mapping[str, Any]) -> None: - """ - Emits the control messages related to configuration migration. - - Args: - - migrated_config (Mapping[str, Any]): The migrated configuration. - """ - cls.message_repository.emit_message(create_connector_config_control_message(migrated_config)) - for message in cls.message_repository._message_queue: - print(message.json(exclude_unset=True)) - - @classmethod - def migrate(cls, args: List[str], source: Source) -> None: - """ - Orchestrates the configuration migration process. - - It first checks if the `--config` argument is provided, and if so, - determines whether migration is needed, and then performs the migration - if required. - - Args: - - args (List[str]): List of command-line arguments. - - source (Source): The data source. - """ - config_path = AirbyteEntrypoint(source).extract_config(args) - if config_path: - config = source.read_config(config_path) - if cls.should_migrate(config): - cls.emit_control_message(cls.modify_and_save(config_path, source, config)) diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/manifest.yaml b/airbyte-integrations/connectors/source-harvest/source_harvest/manifest.yaml deleted file mode 100644 index 4d24a620fb3c..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/manifest.yaml +++ /dev/null @@ -1,2271 +0,0 @@ -version: 0.61.2 - -definitions: - authenticator: - type: SelectiveAuthenticator - authenticator_selection_path: ["credentials", "auth_type"] - authenticators: - Token: - type: BearerAuthenticator - api_token: "{{ config['credentials']['api_token'] }}" - Client: - type: OAuthAuthenticator - client_id: "{{ config['credentials']['client_id'] }}" - grant_type: refresh_token - client_secret: "{{ config['credentials']['client_secret'] }}" - refresh_token: "{{ config['credentials']['refresh_token'] }}" - refresh_request_body: {} - token_refresh_endpoint: https://id.getharvest.com/api/v2/oauth2/token - composite_error_handler: - type: CompositeErrorHandler - error_handlers: - - type: DefaultErrorHandler - backoff_strategies: - - type: WaitTimeFromHeader - header: Retry-After - - type: DefaultErrorHandler - response_filters: - - http_codes: [401] - action: IGNORE - error_message: "Please ensure your credentials are valid." - - http_codes: [403] - action: IGNORE - error_message: "This is most likely due to insufficient permissions on the credentials in use." - - http_codes: [404] - action: IGNORE - error_message: "Please ensure that your account ID is properly set. If it is the case and you are still seeing this error, please contact Airbyte support." -spec: - connection_specification: - $schema: "http://json-schema.org/draft-07/schema#" - title: "Harvest Spec" - type: object - required: - - account_id - - replication_start_date - additionalProperties: true - properties: - account_id: - title: "Account ID" - description: "Harvest account ID. Required for all Harvest requests in pair with Personal Access Token" - airbyte_secret: true - type: string - order: 0 - replication_start_date: - title: "Start Date" - description: "UTC date and time in the format 2017-01-25T00:00:00Z. Any data before this date will not be replicated." - pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$" - examples: - - "2017-01-25T00:00:00Z" - type: string - order: 1 - format: date-time - replication_end_date: - title: "End Date" - description: "UTC date and time in the format 2017-01-25T00:00:00Z. Any data after this date will not be replicated." - pattern: "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$" - examples: - - "2017-01-25T00:00:00Z" - type: string - airbyte_hidden: true - order: 2 - format: date-time - credentials: - title: "Authentication mechanism" - description: "Choose how to authenticate to Harvest." - type: object - order: 3 - oneOf: - - type: object - title: "Authenticate via Harvest (OAuth)" - required: - - client_id - - client_secret - - refresh_token - additionalProperties: true - properties: - auth_type: - type: string - const: "Client" - order: 0 - client_id: - title: "Client ID" - type: string - description: "The Client ID of your Harvest developer application." - client_secret: - title: "Client Secret" - type: string - description: "The Client Secret of your Harvest developer application." - airbyte_secret: true - refresh_token: - title: "Refresh Token" - type: string - description: "Refresh Token to renew the expired Access Token." - airbyte_secret: true - - type: object - title: "Authenticate with Personal Access Token" - required: - - api_token - additionalProperties: true - properties: - auth_type: - type: string - const: "Token" - order: 0 - api_token: - title: "Personal Access Token" - description: 'Log into Harvest and then create new personal access token.' - type: string - airbyte_secret: true -type: DeclarativeSource -check: - type: CheckStream - stream_names: - - company -streams: - - type: DeclarativeStream - name: clients - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /clients - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - clients - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: company - primary_key: [] - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /company - http_method: GET - request_parameters: {} - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: [] - paginator: - type: NoPagination - partition_router: [] - - type: DeclarativeStream - name: contacts - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /contacts - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - contacts - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: estimate_item_categories - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /estimate_item_categories - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - estimate_item_categories - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: estimates - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /estimates - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - estimates - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: expense_categories - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /expense_categories - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - expense_categories - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: expenses - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /expenses - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - expenses - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: invoice_item_categories - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /invoice_item_categories - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - invoice_item_categories - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: invoices - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /invoices - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - invoices - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: projects - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /projects - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - projects - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: roles - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /roles - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - roles - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: task_assignments - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /task_assignments - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - task_assignments - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: tasks - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /tasks - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - tasks - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: time_entries - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /time_entries - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - time_entries - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: user_assignments - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /user_assignments - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - user_assignments - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: users - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /users - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - users - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: expenses_categories - primary_key: [] - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /reports/expenses/categories - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - results - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - transformations: - - type: AddFields - fields: - - path: - - from - value: '"{{ stream_partition.start_time }}"' - - type: AddFields - fields: - - path: - - to - value: '"{{ stream_partition.end_time }}"' - incremental_sync: - type: DatetimeBasedCursor - cursor_field: to - cursor_datetime_formats: - - "%Y%m%d" - datetime_format: "%Y%m%d" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: from - inject_into: request_parameter - end_time_option: - type: RequestOption - field_name: to - inject_into: request_parameter - end_datetime: - type: MinMaxDatetime - datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - step: P365D - cursor_granularity: P1D - - type: DeclarativeStream - name: expenses_clients - primary_key: [] - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /reports/expenses/clients - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - results - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - transformations: - - type: AddFields - fields: - - path: - - from - value: '"{{ stream_partition.start_time }}"' - - type: AddFields - fields: - - path: - - to - value: '"{{ stream_partition.end_time }}"' - incremental_sync: - type: DatetimeBasedCursor - cursor_field: to - cursor_datetime_formats: - - "%Y%m%d" - datetime_format: "%Y%m%d" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: from - inject_into: request_parameter - end_time_option: - type: RequestOption - field_name: to - inject_into: request_parameter - end_datetime: - type: MinMaxDatetime - datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - step: P365D - cursor_granularity: P1D - - type: DeclarativeStream - name: expenses_projects - primary_key: [] - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /reports/expenses/projects - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - results - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - transformations: - - type: AddFields - fields: - - path: - - from - value: '"{{ stream_partition.start_time }}"' - - type: AddFields - fields: - - path: - - to - value: '"{{ stream_partition.end_time }}"' - incremental_sync: - type: DatetimeBasedCursor - cursor_field: to - cursor_datetime_formats: - - "%Y%m%d" - datetime_format: "%Y%m%d" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: from - inject_into: request_parameter - end_time_option: - type: RequestOption - field_name: to - inject_into: request_parameter - end_datetime: - type: MinMaxDatetime - datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - step: P365D - cursor_granularity: P1D - - type: DeclarativeStream - name: expenses_team - primary_key: [] - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /reports/expenses/team - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - results - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - transformations: - - type: AddFields - fields: - - path: - - from - value: '"{{ stream_partition.start_time }}"' - - type: AddFields - fields: - - path: - - to - value: '"{{ stream_partition.end_time }}"' - incremental_sync: - type: DatetimeBasedCursor - cursor_field: to - cursor_datetime_formats: - - "%Y%m%d" - datetime_format: "%Y%m%d" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: from - inject_into: request_parameter - end_time_option: - type: RequestOption - field_name: to - inject_into: request_parameter - end_datetime: - type: MinMaxDatetime - datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - step: P365D - cursor_granularity: P1D - - type: DeclarativeStream - name: project_budget - primary_key: [] - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /reports/project_budget - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - results - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - - type: DeclarativeStream - name: time_clients - primary_key: [] - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /reports/time/clients - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - results - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - transformations: - - type: AddFields - fields: - - path: - - from - value: '"{{ stream_partition.start_time }}"' - - type: AddFields - fields: - - path: - - to - value: '"{{ stream_partition.end_time }}"' - incremental_sync: - type: DatetimeBasedCursor - cursor_field: to - cursor_datetime_formats: - - "%Y%m%d" - datetime_format: "%Y%m%d" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: from - inject_into: request_parameter - end_time_option: - type: RequestOption - field_name: to - inject_into: request_parameter - end_datetime: - type: MinMaxDatetime - datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - step: P365D - cursor_granularity: P1D - - type: DeclarativeStream - name: time_projects - primary_key: [] - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /reports/time/projects - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - results - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - transformations: - - type: AddFields - fields: - - path: - - from - value: '"{{ stream_partition.start_time }}"' - - type: AddFields - fields: - - path: - - to - value: '"{{ stream_partition.end_time }}"' - incremental_sync: - type: DatetimeBasedCursor - cursor_field: to - cursor_datetime_formats: - - "%Y%m%d" - datetime_format: "%Y%m%d" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: from - inject_into: request_parameter - end_time_option: - type: RequestOption - field_name: to - inject_into: request_parameter - end_datetime: - type: MinMaxDatetime - datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - step: P365D - cursor_granularity: P1D - - type: DeclarativeStream - name: time_tasks - primary_key: [] - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /reports/time/tasks - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - results - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - transformations: - - type: AddFields - fields: - - path: - - from - value: '"{{ stream_partition.start_time }}"' - - type: AddFields - fields: - - path: - - to - value: '"{{ stream_partition.end_time }}"' - incremental_sync: - type: DatetimeBasedCursor - cursor_field: to - cursor_datetime_formats: - - "%Y%m%d" - datetime_format: "%Y%m%d" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: from - inject_into: request_parameter - end_time_option: - type: RequestOption - field_name: to - inject_into: request_parameter - end_datetime: - type: MinMaxDatetime - datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - step: P365D - cursor_granularity: P1D - - type: DeclarativeStream - name: time_team - primary_key: [] - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /reports/time/team - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - results - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - transformations: - - type: AddFields - fields: - - path: - - from - value: '"{{ stream_partition.start_time }}"' - - type: AddFields - fields: - - path: - - to - value: '"{{ stream_partition.end_time }}"' - incremental_sync: - type: DatetimeBasedCursor - cursor_field: to - cursor_datetime_formats: - - "%Y%m%d" - datetime_format: "%Y%m%d" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: from - inject_into: request_parameter - end_time_option: - type: RequestOption - field_name: to - inject_into: request_parameter - end_datetime: - type: MinMaxDatetime - datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - step: P365D - cursor_granularity: P1D - - type: DeclarativeStream - name: uninvoiced - primary_key: [] - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /reports/uninvoiced - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - results - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - transformations: - - type: AddFields - fields: - - path: - - from - value: '"{{ stream_partition.start_time }}"' - - type: AddFields - fields: - - path: - - to - value: '"{{ stream_partition.end_time }}"' - incremental_sync: - type: DatetimeBasedCursor - cursor_field: to - cursor_datetime_formats: - - "%Y%m%d" - datetime_format: "%Y%m%d" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: from - inject_into: request_parameter - end_time_option: - type: RequestOption - field_name: to - inject_into: request_parameter - end_datetime: - type: MinMaxDatetime - datetime: "{{ now_utc().strftime('%Y-%m-%dT%H:%M:%SZ') }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - step: P365D - cursor_granularity: P1D - - type: DeclarativeStream - name: estimate_messages - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /estimates/{{stream_partition.id}}/messages - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - estimate_messages - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: - - type: SubstreamPartitionRouter - parent_stream_configs: - - type: ParentStreamConfig - parent_key: id - partition_field: id - stream: - type: DeclarativeStream - name: estimates - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /estimates - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - type: CompositeErrorHandler - error_handlers: - - type: DefaultErrorHandler - backoff_strategies: - - type: WaitTimeFromHeader - header: Retry-After - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - estimates - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - transformations: - - type: AddFields - fields: - - path: - - parent_id - value: "{{stream_partition.id}}" - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: invoice_messages - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /invoices/{{stream_partition.id}}/messages - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - invoice_messages - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: - - type: SubstreamPartitionRouter - parent_stream_configs: - - type: ParentStreamConfig - parent_key: id - partition_field: id - stream: - type: DeclarativeStream - name: invoices - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /invoices - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - type: CompositeErrorHandler - error_handlers: - - type: DefaultErrorHandler - backoff_strategies: - - type: WaitTimeFromHeader - header: Retry-After - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - invoices - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - transformations: - - type: AddFields - fields: - - path: - - parent_id - value: "{{stream_partition.id}}" - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: invoice_payments - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /invoices/{{stream_partition.id}}/payments - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - invoice_payments - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: - - type: SubstreamPartitionRouter - parent_stream_configs: - - type: ParentStreamConfig - parent_key: id - partition_field: id - stream: - type: DeclarativeStream - name: invoices - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /invoices - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - type: CompositeErrorHandler - error_handlers: - - type: DefaultErrorHandler - backoff_strategies: - - type: WaitTimeFromHeader - header: Retry-After - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - invoices - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - transformations: - - type: AddFields - fields: - - path: - - parent_id - value: "{{stream_partition.id}}" - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: project_assignments - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /users/{{stream_partition.id}}/project_assignments - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - project_assignments - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: - - type: SubstreamPartitionRouter - parent_stream_configs: - - type: ParentStreamConfig - parent_key: id - partition_field: id - stream: - type: DeclarativeStream - name: users - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /users - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - type: CompositeErrorHandler - error_handlers: - - type: DefaultErrorHandler - backoff_strategies: - - type: WaitTimeFromHeader - header: Retry-After - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - users - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - transformations: - - type: AddFields - fields: - - path: - - parent_id - value: "{{stream_partition.id}}" - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - - type: DeclarativeStream - name: billable_rates - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /users/{{stream_partition['id']}}/billable_rates - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - billable_rates - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: - - type: SubstreamPartitionRouter - parent_stream_configs: - - type: ParentStreamConfig - parent_key: id - partition_field: id - stream: - type: DeclarativeStream - name: users - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /users - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - type: CompositeErrorHandler - error_handlers: - - type: DefaultErrorHandler - backoff_strategies: - - type: WaitTimeFromHeader - header: Retry-After - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - users - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - transformations: - - type: AddFields - fields: - - path: - - parent_id - value: "{{stream_partition.id}}" - - type: DeclarativeStream - name: cost_rates - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /users/{{stream_partition.id}}/cost_rates - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - $ref: "#/definitions/composite_error_handler" - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - cost_rates - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: - - type: SubstreamPartitionRouter - parent_stream_configs: - - type: ParentStreamConfig - parent_key: id - partition_field: id - stream: - type: DeclarativeStream - name: users - primary_key: - - id - retriever: - type: SimpleRetriever - requester: - type: HttpRequester - url_base: https://api.harvestapp.com/v2/ - path: /users - http_method: GET - request_parameters: - per_page: "50" - request_headers: - Harvest-Account-Id: "{{ config['account_id'] }}" - authenticator: - $ref: "#/definitions/authenticator" - error_handler: - type: CompositeErrorHandler - error_handlers: - - type: DefaultErrorHandler - backoff_strategies: - - type: WaitTimeFromHeader - header: Retry-After - request_body_json: {} - record_selector: - type: RecordSelector - extractor: - type: DpathExtractor - field_path: - - users - paginator: - type: DefaultPaginator - page_token_option: - type: RequestPath - pagination_strategy: - type: CursorPagination - page_size: 1 - cursor_value: '{{ response.get("links", {}).get("next", {}) }}' - stop_condition: '{{ not response.get("links", {}).get("next", {}) }}' - partition_router: [] - incremental_sync: - type: DatetimeBasedCursor - cursor_field: updated_at - cursor_datetime_formats: - - "%Y-%m-%dT%H:%M:%SZ" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_datetime: - type: MinMaxDatetime - datetime: "{{ config['replication_start_date'] }}" - datetime_format: "%Y-%m-%dT%H:%M:%SZ" - start_time_option: - type: RequestOption - field_name: updated_since - inject_into: request_parameter - transformations: - - type: AddFields - fields: - - path: - - parent_id - value: "{{stream_partition.id}}" -metadata: - autoImportSchema: - clients: true - company: true - contacts: true - estimate_item_categories: true - estimates: true - expense_categories: true - expenses: true - invoice_item_categories: true - invoices: true - projects: true - roles: true - task_assignments: true - tasks: true - time_entries: true - user_assignments: true - users: true - expenses_categories: true - expenses_clients: true - expenses_projects: true - expenses_team: true - project_budget: true - time_clients: true - time_projects: true - time_tasks: true - time_team: true - uninvoiced: true - estimate_messages: true - invoice_messages: true - invoice_payments: true - project_assignments: true - billable_rates: true - cost_rates: true diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/run.py b/airbyte-integrations/connectors/source-harvest/source_harvest/run.py deleted file mode 100644 index 9f4222013e93..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/run.py +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - - -import sys - -from airbyte_cdk.entrypoint import launch -from source_harvest import SourceHarvest - -from .config_migrations import MigrateAuthType - - -def run(): - source = SourceHarvest() - MigrateAuthType.migrate(sys.argv[1:], source) - launch(source, sys.argv[1:]) diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/billable_rates.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/billable_rates.json deleted file mode 100644 index 3c259a523ab0..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/billable_rates.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier for this billable rate.", - "type": ["null", "integer"] - }, - "parent_id": { - "description": "The identifier of the parent resource associated with this rate.", - "type": "integer" - }, - "amount": { - "description": "The billable amount associated with this rate.", - "type": ["null", "number"] - }, - "start_date": { - "description": "The start date for this billable rate period.", - "type": ["null", "string"], - "format": "date" - }, - "end_date": { - "description": "The end date for this billable rate period.", - "type": ["null", "string"], - "format": "date" - }, - "created_at": { - "description": "The date and time when this rate was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when this rate was last updated.", - "type": ["null", "string"], - "format": "date-time" - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/clients.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/clients.json deleted file mode 100644 index 974f1c8177b4..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/clients.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "Unique identifier for the client.", - "type": ["null", "integer"] - }, - "name": { - "description": "The client's name.", - "type": ["null", "string"] - }, - "is_active": { - "description": "Indicates whether the client is currently active or not.", - "type": ["null", "boolean"] - }, - "address": { - "description": "The client's postal address.", - "type": ["null", "string"] - }, - "statement_key": { - "description": "Key used for client's statements or invoices.", - "type": ["null", "string"] - }, - "created_at": { - "description": "The date and time when the client record was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the client record was last updated.", - "type": ["null", "string"], - "format": "date-time" - }, - "currency": { - "description": "The currency used by the client.", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/company.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/company.json deleted file mode 100644 index 1d0e8d2ea171..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/company.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "base_uri": { - "description": "The base URI used in constructing URLs for this company.", - "type": ["null", "string"] - }, - "full_domain": { - "description": "The full domain name associated with this company.", - "type": ["null", "string"] - }, - "name": { - "description": "The name of the company.", - "type": ["null", "string"] - }, - "is_active": { - "description": "Indicates if the company is currently active.", - "type": ["null", "boolean"] - }, - "week_start_day": { - "description": "The day considered the start of the week for this company.", - "type": ["null", "string"] - }, - "wants_timestamp_timers": { - "description": "Indicates if the company wants timestamp timers displayed.", - "type": ["null", "boolean"] - }, - "time_format": { - "description": "The format used to display time.", - "type": ["null", "string"] - }, - "plan_type": { - "description": "The type of plan subscribed by the company.", - "type": ["null", "string"] - }, - "expense_feature": { - "description": "Indicates if the expense feature is enabled for this company.", - "type": ["null", "boolean"] - }, - "invoice_feature": { - "description": "Indicates if the invoice feature is enabled for this company.", - "type": ["null", "boolean"] - }, - "estimate_feature": { - "description": "Indicates if the estimate feature is enabled for this company.", - "type": ["null", "boolean"] - }, - "approval_required": { - "description": "Indicates if approval is required for certain actions.", - "type": ["null", "boolean"] - }, - "clock": { - "description": "The clock configuration for time tracking.", - "type": ["null", "string"] - }, - "decimal_symbol": { - "description": "The symbol used to separate the integer part from the fractional part of a number.", - "type": ["null", "string"] - }, - "thousands_separator": { - "description": "The symbol used to separate thousands in a number.", - "type": ["null", "string"] - }, - "color_scheme": { - "description": "The color scheme used in the user interface.", - "type": ["null", "string"] - }, - "weekly_capacity": { - "description": "The weekly capacity setting for this company.", - "type": ["null", "integer"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/contacts.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/contacts.json deleted file mode 100644 index b9f244ca949e..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/contacts.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "Unique identifier for the contact", - "type": ["null", "integer"] - }, - "title": { - "description": "Job title of the contact", - "type": ["null", "string"] - }, - "first_name": { - "description": "First name of the contact", - "type": ["null", "string"] - }, - "last_name": { - "description": "Last name of the contact", - "type": ["null", "string"] - }, - "email": { - "description": "Email address of the contact", - "type": ["null", "string"] - }, - "phone_office": { - "description": "Office phone number of the contact", - "type": ["null", "string"] - }, - "phone_mobile": { - "description": "Mobile phone number of the contact", - "type": ["null", "string"] - }, - "fax": { - "description": "Fax number of the contact", - "type": ["null", "string"] - }, - "created_at": { - "description": "Timestamp of when the contact was created", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "Timestamp of when the contact was last updated", - "type": ["null", "string"], - "format": "date-time" - }, - "client": { - "description": "Details of the client associated with the contact", - "type": ["null", "object"], - "properties": { - "id": { - "description": "Unique identifier for the client", - "type": ["null", "integer"] - }, - "name": { - "description": "Name of the client", - "type": ["null", "string"] - } - } - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/cost_rates.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/cost_rates.json deleted file mode 100644 index 0f61516931a1..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/cost_rates.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier for this cost rate entry.", - "type": ["null", "integer"] - }, - "parent_id": { - "description": "The parent identifier if this cost rate is a child entry.", - "type": "integer" - }, - "amount": { - "description": "The cost rate amount associated with this data entry.", - "type": ["null", "number"] - }, - "start_date": { - "description": "The start date from which the cost rate is valid. Only applicable for intervals.", - "type": ["null", "string"], - "format": "date" - }, - "end_date": { - "description": "The end date for which the cost rate is valid. Only applicable for intervals.", - "type": ["null", "string"], - "format": "date" - }, - "created_at": { - "description": "The timestamp indicating when this cost rate entry was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The timestamp for the last update made to this cost rate entry.", - "type": ["null", "string"], - "format": "date-time" - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/estimate_item_categories.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/estimate_item_categories.json deleted file mode 100644 index 95b9faabbf4b..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/estimate_item_categories.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier for the estimate item category.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the estimate item category.", - "type": ["null", "string"] - }, - "created_at": { - "description": "The date and time when the estimate item category was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the estimate item category was last updated.", - "type": ["null", "string"], - "format": "date-time" - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/estimate_messages.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/estimate_messages.json deleted file mode 100644 index 793c874fd3db..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/estimate_messages.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier for the message.", - "type": ["null", "integer"] - }, - "parent_id": { - "description": "The identifier of the parent message, if this is a reply.", - "type": "integer" - }, - "sent_by": { - "description": "The name of the user who sent the message.", - "type": ["null", "string"] - }, - "sent_by_email": { - "description": "The email address of the user who sent the message.", - "type": ["null", "string"] - }, - "sent_from": { - "description": "The name displayed as the sender.", - "type": ["null", "string"] - }, - "sent_from_email": { - "description": "The email address displayed as the sender.", - "type": ["null", "string"] - }, - "send_me_a_copy": { - "description": "Indicates if the sender requested a copy of the message.", - "type": ["null", "boolean"] - }, - "created_at": { - "description": "The date and time when the message was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the message was last updated.", - "type": ["null", "string"], - "format": "date-time" - }, - "recipients": { - "description": "Details of the recipients of the message.", - "type": ["null", "array"], - "items": { - "properties": { - "email": { - "description": "The email address of a recipient.", - "type": ["string", "null"] - }, - "name": { - "description": "The name of a recipient.", - "type": ["string", "null"] - } - }, - "type": "object" - } - }, - "event_type": { - "description": "The type of event associated with the message.", - "type": ["null", "string"] - }, - "subject": { - "description": "The subject or title of the message.", - "type": ["null", "string"] - }, - "body": { - "description": "The main content of the message.", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/estimates.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/estimates.json deleted file mode 100644 index 958067bcc8af..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/estimates.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier of the estimate.", - "type": ["null", "integer"] - }, - "client_key": { - "description": "The key associated with the client.", - "type": ["null", "string"] - }, - "number": { - "description": "The unique number assigned to the estimate.", - "type": ["null", "string"] - }, - "purchase_order": { - "description": "The purchase order associated with the estimate.", - "type": ["null", "string"] - }, - "amount": { - "description": "The total amount of the estimate.", - "type": ["null", "number"] - }, - "tax": { - "description": "The tax rate applied to the estimate.", - "type": ["null", "number"] - }, - "tax_amount": { - "description": "The total amount of tax applied to the estimate.", - "type": ["null", "number"] - }, - "tax2": { - "description": "An additional tax rate applied to the estimate.", - "type": ["null", "number"] - }, - "tax2_amount": { - "description": "The total amount of the additional tax applied to the estimate.", - "type": ["null", "number"] - }, - "discount": { - "description": "The discount percentage applied to the estimate.", - "type": ["null", "number"] - }, - "discount_amount": { - "description": "The total discount amount applied to the estimate.", - "type": ["null", "number"] - }, - "subject": { - "description": "The subject or description of the estimate.", - "type": ["null", "string"] - }, - "notes": { - "description": "Any additional notes or comments related to the estimate.", - "type": ["null", "string"] - }, - "state": { - "description": "The current state of the estimate (e.g., pending, accepted, declined).", - "type": ["null", "string"] - }, - "issue_date": { - "description": "The date when the estimate was issued.", - "type": ["null", "string"], - "format": "date" - }, - "sent_at": { - "description": "The date and time when the estimate was sent.", - "type": ["null", "string"], - "format": "date-time" - }, - "created_at": { - "description": "The date and time when the estimates was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the estimate was last updated.", - "type": ["null", "string"], - "format": "date-time" - }, - "accepted_at": { - "description": "The date and time when the estimates was accepted.", - "type": ["null", "string"] - }, - "declined_at": { - "description": "The date and time when the estimates was declined.", - "type": ["null", "string"] - }, - "currency": { - "description": "The currency used for the estimate.", - "type": ["null", "string"] - }, - "client": { - "description": "Details about the client associated with the estimates", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the client.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the client.", - "type": ["null", "string"] - } - } - }, - "creator": { - "description": "Information about the creator of the estimates", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the user who created the estimate.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the user who created the estimate.", - "type": ["null", "string"] - } - } - }, - "line_items": { - "description": "The list of line items included in the estimate.", - "type": ["null", "array"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expense_categories.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expense_categories.json deleted file mode 100644 index dce62f35bec6..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expense_categories.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier for the expense category.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the expense category.", - "type": ["null", "string"] - }, - "unit_name": { - "description": "The unit of measurement for the expense category.", - "type": ["null", "string"] - }, - "unit_price": { - "description": "The price per unit of the expense category.", - "type": ["null", "number"] - }, - "is_active": { - "description": "Indicates whether the expense category is currently active or not.", - "type": ["null", "boolean"] - }, - "created_at": { - "description": "The date and time when the expense category was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the expense category was last updated.", - "type": ["null", "string"], - "format": "date-time" - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses.json deleted file mode 100644 index 685b92949594..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses.json +++ /dev/null @@ -1,205 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "Unique identifier for the expense entry", - "type": ["null", "integer"] - }, - "notes": { - "description": "Additional notes or comments for the expense entry", - "type": ["null", "string"] - }, - "total_cost": { - "description": "Total cost of the expense entry", - "type": ["null", "number"] - }, - "units": { - "description": "Number of units (if applicable)", - "type": ["null", "number"] - }, - "is_closed": { - "description": "Indicates if the expense entry is closed", - "type": ["null", "boolean"] - }, - "is_locked": { - "description": "Indicates if the expense entry is locked", - "type": ["null", "boolean"] - }, - "is_billed": { - "description": "Indicates if the expense has been billed to the client", - "type": ["null", "boolean"] - }, - "locked_reason": { - "description": "Reason for locking the expense entry", - "type": ["null", "string"] - }, - "spent_date": { - "description": "Date when the expense was incurred", - "type": ["null", "string"], - "format": "date" - }, - "created_at": { - "description": "Date and time when the expense was created", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "Date and time of the last update to the expense entry", - "type": ["null", "string"], - "format": "date-time" - }, - "billable": { - "description": "Indicates if the expense is billable to the client", - "type": ["null", "boolean"] - }, - "receipt": { - "description": "Details of the receipt attached to the expense", - "type": ["null", "object"], - "properties": { - "url": { - "description": "URL path to access the receipt file", - "type": ["null", "string"] - }, - "file_name": { - "description": "Name of the receipt file", - "type": ["null", "string"] - }, - "file_size": { - "description": "Size of the receipt file", - "type": ["null", "integer"] - }, - "content_type": { - "description": "MIME type of the receipt content", - "type": ["null", "string"] - } - } - }, - "user": { - "description": "Information about the user who incurred the expense", - "type": ["null", "object"], - "properties": { - "id": { - "description": "Unique identifier for the user", - "type": ["null", "integer"] - }, - "name": { - "description": "Name of the user who incurred the expense", - "type": ["null", "string"] - } - } - }, - "user_assignment": { - "description": "Details of the assignment or task associated with the expense", - "type": ["null", "object"], - "properties": { - "id": { - "description": "Unique identifier for the user assignment", - "type": ["null", "integer"] - }, - "is_project_manager": { - "description": "Indicates if the user is a project manager", - "type": ["null", "boolean"] - }, - "is_active": { - "description": "Indicates if the user assignment is active", - "type": ["null", "boolean"] - }, - "budget": { - "description": "Budget allocated for the user assignment", - "type": ["null", "number"] - }, - "created_at": { - "description": "Date and time when the user assignment was created", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "Date and time of the last update to the user assignment", - "type": ["null", "string"], - "format": "date-time" - }, - "hourly_rate": { - "description": "Hourly rate set for the user assignment", - "type": ["null", "number"] - }, - "use_default_rates": { - "description": "Indicates if default rates are used for the user assignment", - "type": ["null", "boolean"] - } - } - }, - "project": { - "description": "Information about the project for which the expense was made", - "type": ["null", "object"], - "properties": { - "id": { - "description": "Unique identifier for the project", - "type": ["null", "integer"] - }, - "name": { - "description": "Name of the project associated with the expense", - "type": ["null", "string"] - }, - "code": { - "description": "Code associated with the project", - "type": ["null", "string"] - } - } - }, - "expense_category": { - "description": "Information about the category of the expense", - "type": ["null", "object"], - "properties": { - "id": { - "description": "Unique identifier for the expense category", - "type": ["null", "integer"] - }, - "name": { - "description": "Name of the expense category", - "type": ["null", "string"] - }, - "unit_price": { - "description": "Price per unit (if applicable)", - "type": ["null", "number"] - }, - "unit_name": { - "description": "Name of the unit (if applicable)", - "type": ["null", "string"] - } - } - }, - "client": { - "description": "Details of the client associated with the expense", - "type": ["null", "object"], - "properties": { - "id": { - "description": "Unique identifier for the client", - "type": ["null", "integer"] - }, - "name": { - "description": "Name of the client associated with the expense", - "type": ["null", "string"] - }, - "currency": { - "description": "Currency used for the client's transactions", - "type": ["null", "string"] - } - } - }, - "invoice": { - "description": "Details of the invoice related to the expense", - "type": ["null", "object"], - "properties": { - "id": { - "description": "Unique identifier for the invoice associated with the expense", - "type": ["null", "integer"] - }, - "number": { - "description": "Invoice number related to the expense", - "type": ["null", "string"] - } - } - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_categories.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_categories.json deleted file mode 100644 index 694ec9cd86b8..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_categories.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "expense_category_id": { - "description": "Unique identifier for the expense category", - "type": ["null", "integer"] - }, - "expense_category_name": { - "description": "Name of the expense category", - "type": ["null", "string"] - }, - "total_amount": { - "description": "Total amount spent on this expense category", - "type": ["null", "number"] - }, - "billable_amount": { - "description": "The amount that can be billed to a client for this expense category", - "type": ["null", "number"] - }, - "currency": { - "description": "The currency in which the expenses are incurred", - "type": ["null", "string"] - }, - "from": { - "description": "Start date for the expenses", - "type": ["null", "string"] - }, - "to": { - "description": "End date for the expenses", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_clients.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_clients.json deleted file mode 100644 index 7e80e309ee66..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_clients.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "client_id": { - "description": "The unique identifier of the client.", - "type": ["null", "integer"] - }, - "client_name": { - "description": "The name of the client associated with the expenses.", - "type": ["null", "string"] - }, - "total_amount": { - "description": "The total amount of expenses including billable and non-billable expenses.", - "type": ["null", "number"] - }, - "billable_amount": { - "description": "The amount billed to the client for the expenses.", - "type": ["null", "number"] - }, - "currency": { - "description": "The currency in which the expenses are recorded.", - "type": ["null", "string"] - }, - "from": { - "description": "The start date of the expense period.", - "type": ["null", "string"] - }, - "to": { - "description": "The end date of the expense period.", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_projects.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_projects.json deleted file mode 100644 index 0152c64c0c35..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_projects.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "client_id": { - "description": "The unique identifier of the client associated with the project", - "type": ["null", "integer"] - }, - "client_name": { - "description": "The name of the client associated with the project", - "type": ["null", "string"] - }, - "project_id": { - "description": "The unique identifier of the project", - "type": ["null", "integer"] - }, - "project_name": { - "description": "The name of the project", - "type": ["null", "string"] - }, - "total_amount": { - "description": "The total amount of expenses incurred for the project", - "type": ["null", "number"] - }, - "billable_amount": { - "description": "The amount of expenses that are billable to the client", - "type": ["null", "number"] - }, - "currency": { - "description": "The currency in which the expenses are recorded", - "type": ["null", "string"] - }, - "from": { - "description": "The starting date of the expense record period", - "type": ["null", "string"] - }, - "to": { - "description": "The ending date of the expense record period", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_team.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_team.json deleted file mode 100644 index 7c6b2ce99ebe..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/expenses_team.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "user_id": { - "description": "The ID of the user associated with the expense", - "type": ["null", "integer"] - }, - "user_name": { - "description": "The name of the user associated with the expense", - "type": ["null", "string"] - }, - "is_contractor": { - "description": "Indicates if the user is a contractor", - "type": ["null", "boolean"] - }, - "total_amount": { - "description": "The total amount of the expense", - "type": ["null", "number"] - }, - "billable_amount": { - "description": "The amount that can be billed for the expense", - "type": ["null", "number"] - }, - "currency": { - "description": "The currency in which the expense is incurred", - "type": ["null", "string"] - }, - "from": { - "description": "The start date of the expense", - "type": ["null", "string"] - }, - "to": { - "description": "The end date of the expense", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoice_item_categories.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoice_item_categories.json deleted file mode 100644 index 50bd7cebeb29..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoice_item_categories.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier for the invoice item category.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the invoice item category.", - "type": ["null", "string"] - }, - "use_as_service": { - "description": "Indicates whether the category is used as a service type.", - "type": ["null", "boolean"] - }, - "use_as_expense": { - "description": "Indicates whether the category is used as an expense type.", - "type": ["null", "boolean"] - }, - "created_at": { - "description": "The date and time when the invoice item category was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the invoice item category was last updated.", - "type": ["null", "string"], - "format": "date-time" - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoice_messages.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoice_messages.json deleted file mode 100644 index d9d934a60dcb..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoice_messages.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier of the invoice message.", - "type": ["null", "integer"] - }, - "parent_id": { - "description": "The ID of the parent message if it's a reply or related message.", - "type": "integer" - }, - "sent_by": { - "description": "The sender of the message.", - "type": ["null", "string"] - }, - "sent_by_email": { - "description": "Email address of the sender.", - "type": ["null", "string"] - }, - "sent_from": { - "description": "The display name of the sender.", - "type": ["null", "string"] - }, - "sent_from_email": { - "description": "Email address used to send the message.", - "type": ["null", "string"] - }, - "include_link_to_client_invoice": { - "description": "Indicates if a link to the client invoice is included.", - "type": ["null", "boolean"] - }, - "send_me_a_copy": { - "description": "Option to send a copy of the message to the sender.", - "type": ["null", "boolean"] - }, - "thank_you": { - "description": "Indicates if the message is a thank you message.", - "type": ["null", "boolean"] - }, - "reminder": { - "description": "Indicates if the message is a reminder.", - "type": ["null", "boolean"] - }, - "send_reminder_on": { - "description": "The date to send a reminder for the message.", - "type": ["null", "string"] - }, - "created_at": { - "description": "The date and time when the message was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the message was last updated.", - "type": ["null", "string"], - "format": "date-time" - }, - "attach_pdf": { - "description": "Indicates if a PDF file is attached to the message.", - "type": ["null", "boolean"] - }, - "event_type": { - "description": "The type of event associated with the message.", - "type": ["null", "string"] - }, - "recipients": { - "description": "List of recipients for the message.", - "type": ["null", "array"], - "items": { - "properties": { - "email": { - "description": "Email address of the recipient.", - "type": "string" - }, - "name": { - "description": "Name of the recipient.", - "type": "string" - } - }, - "type": "object" - } - }, - "subject": { - "description": "The subject of the invoice message.", - "type": ["null", "string"] - }, - "body": { - "description": "The content of the invoice message.", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoice_payments.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoice_payments.json deleted file mode 100644 index e3ab8e67bfe3..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoice_payments.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier of the invoice payment.", - "type": ["null", "integer"] - }, - "parent_id": { - "description": "The ID of the parent invoice associated with this payment.", - "type": "integer" - }, - "amount": { - "description": "The amount of the invoice payment.", - "type": ["null", "number"] - }, - "paid_at": { - "description": "The timestamp when the invoice payment was paid.", - "type": ["null", "string"], - "format": "date-time" - }, - "paid_date": { - "description": "The date when the invoice payment was paid.", - "type": ["null", "string"], - "format": "date" - }, - "recorded_by": { - "description": "The user who recorded this invoice payment.", - "type": ["null", "string"] - }, - "recorded_by_email": { - "description": "The email address of the user who recorded this invoice payment.", - "type": ["null", "string"] - }, - "notes": { - "description": "Any additional notes or comments related to the invoice payment.", - "type": ["null", "string"] - }, - "transaction_id": { - "description": "The transaction ID associated with the invoice payment.", - "type": ["null", "string"] - }, - "created_at": { - "description": "The timestamp when the invoice payment was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The timestamp when the invoice payment was last updated.", - "type": ["null", "string"], - "format": "date-time" - }, - "payment_gateway": { - "description": "Information about the payment gateway used for the transaction.", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the payment gateway.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the payment gateway.", - "type": ["null", "string"] - } - } - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoices.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoices.json deleted file mode 100644 index 804304d4e231..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/invoices.json +++ /dev/null @@ -1,220 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier of the invoice", - "type": ["null", "integer"] - }, - "client_key": { - "description": "Key associated with the client", - "type": ["null", "string"] - }, - "number": { - "description": "Invoice number", - "type": ["null", "string"] - }, - "purchase_order": { - "description": "Purchase order related to the invoice", - "type": ["null", "string"] - }, - "amount": { - "description": "The total amount of the invoice", - "type": ["null", "number"] - }, - "due_amount": { - "description": "The remaining amount that is due", - "type": ["null", "number"] - }, - "tax": { - "description": "Tax amount applied", - "type": ["null", "number"] - }, - "tax_amount": { - "description": "Total amount of tax applied", - "type": ["null", "number"] - }, - "tax2": { - "description": "Additional tax amount applied at a different rate", - "type": ["null", "number"] - }, - "tax2_amount": { - "description": "Total amount of tax2 applied", - "type": ["null", "number"] - }, - "discount": { - "description": "Discount percentage applied to the invoice", - "type": ["null", "number"] - }, - "discount_amount": { - "description": "The total discount amount applied", - "type": ["null", "number"] - }, - "subject": { - "description": "Subject of the invoice", - "type": ["null", "string"] - }, - "notes": { - "description": "Additional notes related to the invoice", - "type": ["null", "string"] - }, - "state": { - "description": "Current state of the invoice", - "type": ["null", "string"] - }, - "period_start": { - "description": "Start date of the period covered by the invoice", - "type": ["null", "string"] - }, - "period_end": { - "description": "End date of the period covered by the invoice", - "type": ["null", "string"] - }, - "issue_date": { - "description": "Date when the invoice was issued", - "type": ["null", "string"] - }, - "due_date": { - "description": "Due date for the invoice payment", - "type": ["null", "string"] - }, - "payment_term": { - "description": "Payment terms associated with the invoice", - "type": ["null", "string"] - }, - "sent_at": { - "description": "Timestamp when the invoice was sent", - "type": ["null", "string"], - "format": "date-time" - }, - "paid_at": { - "description": "Timestamp when the invoice was paid", - "type": ["null", "string"] - }, - "paid_date": { - "description": "Date when the invoice was paid", - "type": ["null", "string"] - }, - "closed_at": { - "description": "Timestamp when the invoice was closed", - "type": ["null", "string"] - }, - "recurring_invoice_id": { - "description": "Unique identifier of the recurring invoice", - "type": ["null", "string"] - }, - "created_at": { - "description": "Timestamp when the invoice was created", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "Timestamp when the invoice was last updated", - "type": ["null", "string"], - "format": "date-time" - }, - "currency": { - "description": "The currency used for the invoice", - "type": ["null", "string"] - }, - "client": { - "description": "Details of the client associated with the invoice", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the client", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the client", - "type": ["null", "string"] - } - } - }, - "estimate": { - "description": "Whether the invoice is an estimate", - "type": ["null", "string"] - }, - "retainer": { - "description": "Whether the invoice is for a retainer", - "type": ["null", "string"] - }, - "creator": { - "description": "Information about the creator of the invoice", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the creator", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the creator", - "type": ["null", "string"] - } - } - }, - "line_items": { - "description": "List of line items containing the services/products included in the invoice", - "type": ["null", "array"], - "items": { - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the line item", - "type": ["null", "integer"] - }, - "kind": { - "description": "Type of line item", - "type": ["null", "string"] - }, - "description": { - "description": "Description of the line item", - "type": ["null", "string"] - }, - "quantity": { - "description": "Quantity of the line item", - "type": ["null", "number"] - }, - "unit_price": { - "description": "Unit price of the line item", - "type": ["null", "number"] - }, - "amount": { - "description": "The amount per line item", - "type": ["null", "number"] - }, - "taxed": { - "description": "Whether the line item is taxed", - "type": ["null", "boolean"] - }, - "taxed2": { - "description": "Whether the line item is taxed at a different rate", - "type": ["null", "boolean"] - }, - "project": { - "description": "Details of the project related to the line item", - "type": ["null", "object"], - "properties": { - "code": { - "description": "Project code of the line item", - "type": ["null", "string"] - }, - "id": { - "description": "The unique identifier of the project", - "type": ["integer", "null"] - }, - "name": { - "description": "Name of the project", - "type": ["null", "string"] - } - } - } - } - } - }, - "payment_options": { - "description": "Payment options available for the invoice", - "type": ["null", "array"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/project_assignments.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/project_assignments.json deleted file mode 100644 index a26384b336b0..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/project_assignments.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier of the project assignment", - "type": ["null", "integer"] - }, - "parent_id": { - "description": "The parent project assignment ID if this assignment is a sub-assignment", - "type": "integer" - }, - "is_project_manager": { - "description": "Indicates whether the user is assigned as a project manager", - "type": ["null", "boolean"] - }, - "is_active": { - "description": "Indicates whether the project assignment is currently active", - "type": ["null", "boolean"] - }, - "use_default_rates": { - "description": "Indicates whether default rates are used for this project assignment", - "type": ["null", "boolean"] - }, - "budget": { - "description": "The budget allocated for this project assignment", - "type": ["null", "number"] - }, - "created_at": { - "description": "The date and time when the project assignment was created", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the project assignment was last updated", - "type": ["null", "string"], - "format": "date-time" - }, - "hourly_rate": { - "description": "The hourly rate for this project assignment", - "type": ["null", "number"] - }, - "project": { - "description": "Project information for the assignment", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the project", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the project", - "type": ["null", "string"] - }, - "code": { - "description": "The code associated with the project", - "type": ["null", "string"] - } - } - }, - "client": { - "description": "Client information for the project assignment", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the client", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the client", - "type": ["null", "string"] - }, - "currency": { - "description": "The currency used by the client", - "type": ["null", "string"] - } - } - }, - "task_assignments": { - "description": "List of task assignments for the project", - "type": ["null", "array"], - "items": { - "properties": { - "billable": { - "description": "Indicates whether the task is billable", - "type": ["null", "boolean"] - }, - "budget": { - "description": "The budget allocated for this task assignment", - "type": ["null", "number"] - }, - "created_at": { - "description": "The date and time when the task assignment was created", - "type": ["string", "null"] - }, - "hourly_rate": { - "description": "The hourly rate for this task assignment", - "type": ["null", "number"] - }, - "id": { - "description": "The unique identifier of the task assignment", - "type": ["null", "integer"] - }, - "is_active": { - "description": "Indicates whether the task assignment is currently active", - "type": ["null", "boolean"] - }, - "task": { - "description": "Information about a specific task assigned", - "properties": { - "id": { - "description": "The unique identifier of the task", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the task", - "type": ["null", "string"] - } - }, - "type": ["object", "null"] - }, - "updated_at": { - "description": "The date and time when the task assignment was last updated", - "type": ["null", "string"] - } - }, - "type": "object" - } - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/project_budget.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/project_budget.json deleted file mode 100644 index c276ca42e9e2..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/project_budget.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "project_id": { - "description": "Unique identifier for the project", - "type": ["null", "integer"] - }, - "project_name": { - "description": "Name of the project", - "type": ["null", "string"] - }, - "client_id": { - "description": "Unique identifier for the client associated with the project", - "type": ["null", "integer"] - }, - "client_name": { - "description": "Name of the client associated with the project", - "type": ["null", "string"] - }, - "budget_is_monthly": { - "description": "Indicates if the budget is calculated on a monthly basis", - "type": ["null", "boolean"] - }, - "budget_by": { - "description": "Person or entity responsible for the budget", - "type": ["null", "string"] - }, - "is_active": { - "description": "Indicates if the project is currently active", - "type": ["null", "boolean"] - }, - "budget": { - "description": "Total budget allocated for the project", - "type": ["null", "number"] - }, - "budget_spent": { - "description": "Total amount spent from the budget", - "type": ["null", "number"] - }, - "budget_remaining": { - "description": "Remaining budget amount available for the project", - "type": ["null", "number"] - }, - "from": { - "description": "Start date of the budget period", - "type": ["null", "string"] - }, - "to": { - "description": "End date of the budget period", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/projects.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/projects.json deleted file mode 100644 index 483455e4408e..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/projects.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier of the project.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name or title of the project.", - "type": ["null", "string"] - }, - "code": { - "description": "A unique identifier or code for the project.", - "type": ["null", "string"] - }, - "is_active": { - "description": "Indicates whether the project is currently active.", - "type": ["null", "boolean"] - }, - "bill_by": { - "description": "Indicates how the project is billed, e.g., hourly, fixed fee, etc.", - "type": ["null", "string"] - }, - "budget": { - "description": "The allocated budget for the project.", - "type": ["null", "number"] - }, - "budget_by": { - "description": "Specifies how the budget is managed, e.g., total, task, person, etc.", - "type": ["null", "string"] - }, - "budget_is_monthly": { - "description": "Indicates whether the budget is monthly.", - "type": ["null", "boolean"] - }, - "notify_when_over_budget": { - "description": "Indicates whether notifications are sent when the project goes over budget.", - "type": ["null", "boolean"] - }, - "over_budget_notification_percentage": { - "description": "The percentage threshold for over-budget notifications.", - "type": ["null", "number"] - }, - "over_budget_notification_date": { - "description": "The date for sending notifications when the project goes over budget.", - "type": ["null", "string"], - "format": "date" - }, - "show_budget_to_all": { - "description": "Indicates whether the budget is visible to all project members.", - "type": ["null", "boolean"] - }, - "created_at": { - "description": "The date and time when the project was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the project was last updated.", - "type": ["null", "string"], - "format": "date-time" - }, - "starts_on": { - "description": "The start date of the project.", - "type": ["null", "string"], - "format": "date" - }, - "ends_on": { - "description": "The end date of the project.", - "type": ["null", "string"] - }, - "is_billable": { - "description": "Indicates whether the project is billable.", - "type": ["null", "boolean"] - }, - "is_fixed_fee": { - "description": "Indicates whether the project has a fixed fee.", - "type": ["null", "boolean"] - }, - "notes": { - "description": "Any additional notes or comments related to the project.", - "type": ["null", "string"] - }, - "client": { - "description": "Details of the client associated with the project.", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the client.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the client associated with the project.", - "type": ["null", "string"] - }, - "currency": { - "description": "The currency used for the project.", - "type": ["null", "string"] - } - } - }, - "cost_budget": { - "description": "The total cost budget for the project.", - "type": ["null", "number"] - }, - "cost_budget_include_expenses": { - "description": "Indicates whether expenses are included in the cost budget.", - "type": ["null", "boolean"] - }, - "hourly_rate": { - "description": "The hourly rate for the project.", - "type": ["null", "number"] - }, - "fee": { - "description": "The fee associated with the project.", - "type": ["null", "number"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/roles.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/roles.json deleted file mode 100644 index 975c6f1da097..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/roles.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier for the role", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the role", - "type": ["null", "string"] - }, - "created_at": { - "description": "The date and time when the role was created", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the role was last updated", - "type": ["null", "string"], - "format": "date-time" - }, - "user_ids": { - "description": "An array of user IDs associated with the role", - "type": ["null", "array"], - "items": { - "description": "The unique identifier for a user assigned to this role", - "type": "integer" - } - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/task_assignments.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/task_assignments.json deleted file mode 100644 index 339780b9eca4..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/task_assignments.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "Unique identifier for the task assignment", - "type": ["null", "integer"] - }, - "billable": { - "description": "Indicates if the task assignment is billable or not", - "type": ["null", "boolean"] - }, - "is_active": { - "description": "Indicates if the task assignment is currently active", - "type": ["null", "boolean"] - }, - "created_at": { - "description": "The date and time when the task assignment was created", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the task assignment was last updated", - "type": ["null", "string"], - "format": "date-time" - }, - "hourly_rate": { - "description": "The hourly rate for this task assignment", - "type": ["null", "number"] - }, - "budget": { - "description": "The budget allocated for this task assignment", - "type": ["null", "string"] - }, - "project": { - "description": "Details about the project the task assignment is associated with.", - "type": ["null", "object"], - "properties": { - "id": { - "description": "Unique identifier for the project", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the project", - "type": ["null", "string"] - }, - "code": { - "description": "The code assigned to the project", - "type": ["null", "string"] - } - } - }, - "task": { - "description": "Information related to the task assigned.", - "type": ["null", "object"], - "properties": { - "id": { - "description": "Unique identifier for the task", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the task", - "type": ["null", "string"] - } - } - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/tasks.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/tasks.json deleted file mode 100644 index 5b7af4fc32b9..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/tasks.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "Unique identifier for the task.", - "type": ["null", "integer"] - }, - "name": { - "description": "Name of the task.", - "type": ["null", "string"] - }, - "billable_by_default": { - "description": "Indicates if the task is billable by default for the project.", - "type": ["null", "boolean"] - }, - "default_hourly_rate": { - "description": "Default hourly rate set for the task.", - "type": ["null", "number"] - }, - "is_default": { - "description": "Indicates if the task is the default task for the project.", - "type": ["null", "boolean"] - }, - "is_active": { - "description": "Indicates if the task is active or not.", - "type": ["null", "boolean"] - }, - "created_at": { - "description": "Timestamp for when the task was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "Timestamp for when the task was last updated.", - "type": ["null", "string"], - "format": "date-time" - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_clients.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_clients.json deleted file mode 100644 index c52bcbdd69b4..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_clients.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "client_id": { - "description": "The unique identifier of the client associated with the time entries.", - "type": ["null", "integer"] - }, - "client_name": { - "description": "The name of the client for whom the time entries were recorded.", - "type": ["null", "string"] - }, - "total_hours": { - "description": "The total number of hours worked for the client within the specified timeframe, including both billable and non-billable hours.", - "type": ["null", "number"] - }, - "billable_hours": { - "description": "The total number of billable hours worked for the client within the specified timeframe.", - "type": ["null", "number"] - }, - "currency": { - "description": "The currency used for billing the client's time entries.", - "type": ["null", "string"] - }, - "billable_amount": { - "description": "The amount that can be billed for the client's hours worked within the specified timeframe.", - "type": ["null", "number"] - }, - "from": { - "description": "The start date and time of the timeframe for which the time entries are being fetched.", - "type": ["null", "string"] - }, - "to": { - "description": "The end date and time of the timeframe for which the time entries are being fetched.", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_entries.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_entries.json deleted file mode 100644 index 9fd2a2ba263c..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_entries.json +++ /dev/null @@ -1,243 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier of the time entry.", - "type": ["null", "integer"] - }, - "spent_date": { - "description": "The date when the time was spent.", - "type": ["null", "string"], - "format": "date" - }, - "user": { - "description": "The user who created the time entry", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the user.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the user.", - "type": ["null", "string"] - } - } - }, - "client": { - "description": "The client associated with the time entry", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the client.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the client.", - "type": ["null", "string"] - }, - "currency": { - "description": "The currency used by the client.", - "type": ["null", "string"] - } - } - }, - "project": { - "description": "The project where the time entry was tracked", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the project.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the project.", - "type": ["null", "string"] - }, - "code": { - "description": "The project code associated with the time entry.", - "type": ["null", "string"] - } - } - }, - "task": { - "description": "The task performed during the time entry", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the task.", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the task.", - "type": ["null", "string"] - } - } - }, - "user_assignment": { - "description": "The user assignment details for the time entry", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the user assignment.", - "type": ["null", "integer"] - }, - "is_project_manager": { - "description": "Indicates if the user is a project manager.", - "type": ["null", "boolean"] - }, - "is_active": { - "description": "Indicates if the user assignment is active.", - "type": ["null", "boolean"] - }, - "budget": { - "description": "The budget associated with the user assignment.", - "type": ["null", "number"] - }, - "created_at": { - "description": "The date and time when the user assignment was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the user assignment was last updated.", - "type": ["null", "string"], - "format": "date-time" - }, - "hourly_rate": { - "description": "The hourly rate associated with the user assignment.", - "type": ["null", "number"] - } - } - }, - "task_assignment": { - "description": "The task assignment details for the time entry", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the task assignment.", - "type": ["null", "integer"] - }, - "billable": { - "description": "Indicates if the task assignment is billable.", - "type": ["null", "boolean"] - }, - "is_active": { - "description": "Indicates if the task assignment is active.", - "type": ["null", "boolean"] - }, - "created_at": { - "description": "The date and time when the task assignment was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the task assignment was last updated.", - "type": ["null", "string"], - "format": "date-time" - }, - "hourly_rate": { - "description": "The hourly rate associated with the task assignment.", - "type": ["null", "number"] - }, - "budget": { - "description": "The budget associated with the task assignment.", - "type": ["null", "number"] - } - } - }, - "hours": { - "description": "The total hours logged in the time entry.", - "type": ["null", "number"] - }, - "hours_without_timer": { - "description": "Hours logged without using a timer.", - "type": ["null", "number"] - }, - "rounded_hours": { - "description": "The total hours rounded to a specific precision.", - "type": ["null", "number"] - }, - "notes": { - "description": "Any additional notes associated with the time entry.", - "type": ["null", "string"] - }, - "created_at": { - "description": "The date and time when the time entry was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the time entry was last updated.", - "type": ["null", "string"], - "format": "date-time" - }, - "is_locked": { - "description": "Indicates if the time entry is locked.", - "type": ["null", "boolean"] - }, - "locked_reason": { - "description": "The reason why the time entry is locked.", - "type": ["null", "string"] - }, - "is_closed": { - "description": "Indicates if the time entry is closed.", - "type": ["null", "boolean"] - }, - "is_billed": { - "description": "Indicates if the time entry has been billed.", - "type": ["null", "boolean"] - }, - "timer_started_at": { - "description": "The time when the timer for the time entry was started.", - "type": ["null", "string"] - }, - "started_time": { - "description": "The time when the time entry started.", - "type": ["null", "string"] - }, - "ended_time": { - "description": "The time when the time entry ended.", - "type": ["null", "string"] - }, - "is_running": { - "description": "Indicates if the time entry is currently running.", - "type": ["null", "boolean"] - }, - "invoice": { - "description": "The invoice related to the time entry", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the associated invoice.", - "type": "integer" - }, - "number": { - "description": "The invoice number associated with the time entry.", - "type": "string" - } - } - }, - "external_reference": { - "description": "An external reference linked to the time entry.", - "type": ["null", "string"] - }, - "billable": { - "description": "Indicates if the time entry is billable or not.", - "type": ["null", "boolean"] - }, - "budgeted": { - "description": "Indicates if the time entry is within the budget.", - "type": ["null", "boolean"] - }, - "billable_rate": { - "description": "The rate at which the time entry is billable.", - "type": ["null", "number"] - }, - "cost_rate": { - "description": "The cost rate associated with the time entry.", - "type": ["null", "number"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_projects.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_projects.json deleted file mode 100644 index a21889fd34a0..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_projects.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "project_id": { - "description": "The unique identifier for the project.", - "type": ["null", "integer"] - }, - "project_name": { - "description": "The name of the project.", - "type": ["null", "string"] - }, - "client_id": { - "description": "The unique identifier for the client associated with this project.", - "type": ["null", "integer"] - }, - "client_name": { - "description": "The name of the client associated with this project.", - "type": ["null", "string"] - }, - "total_hours": { - "description": "The total number of hours spent on this project.", - "type": ["null", "number"] - }, - "billable_hours": { - "description": "The number of billable hours spent on this project.", - "type": ["null", "number"] - }, - "currency": { - "description": "The currency in which the billable amount is specified.", - "type": ["null", "string"] - }, - "billable_amount": { - "description": "The total amount that can be billed for this project in the given currency.", - "type": ["null", "number"] - }, - "from": { - "description": "The start date for the project time frame.", - "type": ["null", "string"] - }, - "to": { - "description": "The end date for the project time frame.", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_tasks.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_tasks.json deleted file mode 100644 index 76d9d5c96a47..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_tasks.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "task_id": { - "description": "The unique identifier for the task associated with this time entry", - "type": ["null", "integer"] - }, - "task_name": { - "description": "The name of the task associated with this time entry", - "type": ["null", "string"] - }, - "total_hours": { - "description": "The total number of hours spent on this time task", - "type": ["null", "number"] - }, - "billable_hours": { - "description": "The number of hours that can be billed for this time task", - "type": ["null", "number"] - }, - "currency": { - "description": "The currency in which the billable amount is calculated", - "type": ["null", "string"] - }, - "billable_amount": { - "description": "The amount that can be billed for this time task", - "type": ["null", "number"] - }, - "from": { - "description": "The starting time of the time task", - "type": ["null", "string"] - }, - "to": { - "description": "The ending time of the time task", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_team.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_team.json deleted file mode 100644 index 2e40a11d5590..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/time_team.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "user_id": { - "description": "The unique identifier of the user", - "type": ["null", "integer"] - }, - "user_name": { - "description": "The name of the user", - "type": ["null", "string"] - }, - "is_contractor": { - "description": "Flag indicating if the user is a contractor", - "type": ["null", "boolean"] - }, - "total_hours": { - "description": "The total number of hours worked for the time period", - "type": ["null", "number"] - }, - "billable_hours": { - "description": "The number of hours that can be billed for the time period", - "type": ["null", "number"] - }, - "currency": { - "description": "The currency used for billing", - "type": ["null", "string"] - }, - "billable_amount": { - "description": "The amount that can be billed for the time period", - "type": ["null", "number"] - }, - "from": { - "description": "The start date and time of the time period", - "type": ["null", "string"] - }, - "to": { - "description": "The end date and time of the time period", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/uninvoiced.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/uninvoiced.json deleted file mode 100644 index fc471724bd48..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/uninvoiced.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "client_id": { - "description": "Unique identifier for the client", - "type": ["null", "integer"] - }, - "client_name": { - "description": "Name of the client", - "type": ["null", "string"] - }, - "project_id": { - "description": "Unique identifier for the project", - "type": ["null", "integer"] - }, - "project_name": { - "description": "Name of the project", - "type": ["null", "string"] - }, - "currency": { - "description": "Currency used for the transaction", - "type": ["null", "string"] - }, - "total_hours": { - "description": "Total hours tracked for the project within the data range", - "type": ["null", "number"] - }, - "uninvoiced_hours": { - "description": "Total hours yet to be invoiced for the project within the data range", - "type": ["null", "number"] - }, - "uninvoiced_expenses": { - "description": "Total expenses yet to be invoiced for the project within the data range", - "type": ["null", "number"] - }, - "uninvoiced_amount": { - "description": "Total amount yet to be invoiced for the project within the data range", - "type": ["null", "number"] - }, - "from": { - "description": "Start date for the data range", - "type": ["null", "string"] - }, - "to": { - "description": "End date for the data range", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/user_assignments.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/user_assignments.json deleted file mode 100644 index f196ca28830a..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/user_assignments.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "The unique identifier for the assignment", - "type": ["null", "integer"] - }, - "is_project_manager": { - "description": "Flag indicating if the user is a project manager for the assignment", - "type": ["null", "boolean"] - }, - "is_active": { - "description": "Flag indicating if the assignment is currently active", - "type": ["null", "boolean"] - }, - "use_default_rates": { - "description": "Flag indicating if default rates are used for the assignment", - "type": ["null", "boolean"] - }, - "budget": { - "description": "The budget allocated for the assignment", - "type": ["null", "number"] - }, - "created_at": { - "description": "The date and time when the assignment was created", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "The date and time when the assignment was last updated", - "type": ["null", "string"], - "format": "date-time" - }, - "hourly_rate": { - "description": "The hourly rate for the assignment", - "type": ["null", "number"] - }, - "project": { - "description": "Details of the project the user is assigned to.", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the project", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the project associated with the assignment", - "type": ["null", "string"] - }, - "code": { - "description": "The project code associated with the assignment", - "type": ["null", "string"] - } - } - }, - "user": { - "description": "Details of the user assignment.", - "type": ["null", "object"], - "properties": { - "id": { - "description": "The unique identifier of the user assigned to the project", - "type": ["null", "integer"] - }, - "name": { - "description": "The name of the user assigned to the project", - "type": ["null", "string"] - } - } - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/users.json b/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/users.json deleted file mode 100644 index 91e429be4843..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/schemas/users.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "id": { - "description": "Unique identifier for the user.", - "type": ["null", "integer"] - }, - "first_name": { - "description": "User's first name.", - "type": ["null", "string"] - }, - "last_name": { - "description": "User's last name.", - "type": ["null", "string"] - }, - "email": { - "description": "User's email address.", - "type": ["null", "string"] - }, - "telephone": { - "description": "User's telephone number.", - "type": ["null", "string"] - }, - "timezone": { - "description": "User's timezone.", - "type": ["null", "string"] - }, - "has_access_to_all_future_projects": { - "description": "Indicates if the user has access to all future projects.", - "type": ["null", "boolean"] - }, - "is_contractor": { - "description": "Shows if the user is a contractor.", - "type": ["null", "boolean"] - }, - "is_admin": { - "description": "Indicates if the user is an admin.", - "type": ["null", "boolean"] - }, - "is_project_manager": { - "description": "Indicates if the user is a project manager.", - "type": ["null", "boolean"] - }, - "can_see_rates": { - "description": "Indicates if the user can see rates.", - "type": ["null", "boolean"] - }, - "can_create_projects": { - "description": "Shows if the user can create projects.", - "type": ["null", "boolean"] - }, - "can_create_invoices": { - "description": "Shows if the user can create invoices.", - "type": ["null", "boolean"] - }, - "is_active": { - "description": "Shows if the user is currently active.", - "type": ["null", "boolean"] - }, - "created_at": { - "description": "Date and time when the user was created.", - "type": ["null", "string"], - "format": "date-time" - }, - "updated_at": { - "description": "Date and time when the user record was last updated.", - "type": ["null", "string"], - "format": "date-time" - }, - "weekly_capacity": { - "description": "User's weekly capacity for work.", - "type": ["null", "integer"] - }, - "default_hourly_rate": { - "description": "User's default hourly rate for billing.", - "type": ["null", "number"] - }, - "cost_rate": { - "description": "The cost rate associated with the user.", - "type": ["null", "number"] - }, - "roles": { - "description": "List of roles associated with the user.", - "type": ["null", "array"], - "items": { - "type": "string" - } - }, - "avatar_url": { - "description": "URL of the user's avatar image.", - "type": ["null", "string"] - }, - "calendar_integration_enabled": { - "description": "Indicates if calendar integration is enabled for the user.", - "type": ["null", "boolean"] - }, - "calendar_integration_source": { - "description": "Source of calendar integration for the user.", - "type": ["null", "string"] - } - } -} diff --git a/airbyte-integrations/connectors/source-harvest/source_harvest/source.py b/airbyte-integrations/connectors/source-harvest/source_harvest/source.py deleted file mode 100644 index 8bf4afedbc0c..000000000000 --- a/airbyte-integrations/connectors/source-harvest/source_harvest/source.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from airbyte_cdk.sources.declarative.yaml_declarative_source import YamlDeclarativeSource - -""" -This file provides the necessary constructs to interpret a provided declarative YAML configuration file into -source connector. - -WARNING: Do not modify this file. -""" - - -# Declarative Source -class SourceHarvest(YamlDeclarativeSource): - def __init__(self): - super().__init__(**{"path_to_yaml": "manifest.yaml"}) diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/config.py b/airbyte-integrations/connectors/source-harvest/unit_tests/config.py deleted file mode 100644 index 1156237c441e..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/config.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. - -from datetime import datetime -from typing import Any, Dict - - -class ConfigBuilder: - def __init__(self) -> None: - self._config: Dict[str, Any] = { - "account_id": "an account id", - "replication_start_date": "2021-01-01T00:00:00Z", - "credentials": { - "api_token": "an api key", - "auth_type": "Token" - } - } - - def with_account_id(self, account_id: str) -> "ConfigBuilder": - self._config["account_id"] = account_id - return self - - def with_replication_start_date(self, replication_start_date: datetime) -> "ConfigBuilder": - self._config["replication_start_date"] = replication_start_date.strftime('%Y-%m-%dT%H:%M:%SZ') - return self - - def with_api_token(self, api_token: str) -> "ConfigBuilder": - self._config["credentials"]["api_token"] = api_token - return self - - def with_client_id(self, client_id: str) -> "ConfigBuilder": - self._config["credentials"]["client_id"] = client_id - return self - - def with_auth_type(self, auth_type: str) -> "ConfigBuilder": - self._config["credentials"]["auth_type"] = auth_type - return self - - def build(self) -> Dict[str, Any]: - return self._config diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/conftest.py b/airbyte-integrations/connectors/source-harvest/unit_tests/conftest.py deleted file mode 100644 index 259dbdb56c62..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/conftest.py +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from pendulum import parse -from pytest import fixture - - -@fixture(name="config") -def config_fixture(requests_mock): - url = "https://id.getharvest.com/api/v2/oauth2/token" - requests_mock.get(url, json={}) - config = {"account_id": "ID", "replication_start_date": "2021-01-01T21:20:07Z", "credentials": {"auth_type": "Token", "api_token": "TOKEN"}} - return config - - -@fixture(name="replication_start_date") -def replication_start_date_fixture(config): - return parse(config["replication_start_date"]) - - -@fixture(name="from_date") -def from_date_fixture(replication_start_date): - return replication_start_date.date() - - -@fixture(name="mock_stream") -def mock_stream_fixture(requests_mock): - def _mock_stream(path, response=None): - if response is None: - response = {} - - url = f"https://api.harvestapp.com/v2/{path}" - requests_mock.get(url, json=response) - - return _mock_stream diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/integration/__init__.py b/airbyte-integrations/connectors/source-harvest/unit_tests/integration/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/integration/test_invoice_messages.py b/airbyte-integrations/connectors/source-harvest/unit_tests/integration/test_invoice_messages.py deleted file mode 100644 index 6e0fa98cc0b7..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/integration/test_invoice_messages.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. - -from datetime import datetime -from typing import Any, Dict, Optional -from unittest import TestCase - -from airbyte_cdk.test.catalog_builder import CatalogBuilder -from airbyte_cdk.test.entrypoint_wrapper import EntrypointOutput, read -from airbyte_cdk.test.mock_http import HttpMocker, HttpRequest -from airbyte_cdk.test.mock_http.response_builder import ( - FieldPath, - HttpResponseBuilder, - RecordBuilder, - create_record_builder, - create_response_builder, - find_template, -) -from airbyte_protocol.models import SyncMode -from config import ConfigBuilder -from source_harvest import SourceHarvest - -_A_START_DATE = "2021-01-01T00:00:00+00:00" -_AN_ACCOUNT_ID = "1209384" -_AN_API_KEY = "harvestapikey" -_AN_INVOICE_ID = "an-invoice-id" -_STREAM_NAME = "invoice_messages" -_TEMPLATE_NAME = "invoice_messages" -_INVOICES_TEMPLATE_NAME = "invoices" -_RECORDS_PATH = FieldPath("invoice_messages") -_INVOICES_RECORDS_PATH = FieldPath("invoices") - - -def _a_message() -> RecordBuilder: - return create_record_builder( - find_template(_TEMPLATE_NAME, __file__), - _RECORDS_PATH, - ) - - -def _invoice_messages_response() -> HttpResponseBuilder: - return create_response_builder( - find_template(_TEMPLATE_NAME, __file__), - _RECORDS_PATH, - ) - - -def _an_invoice() -> RecordBuilder: - return create_record_builder( - find_template(_INVOICES_TEMPLATE_NAME, __file__), - _INVOICES_RECORDS_PATH, - record_id_path=FieldPath("id"), - ) - - -def _invoices_response() -> HttpResponseBuilder: - return create_response_builder( - find_template(_INVOICES_TEMPLATE_NAME, __file__), - _INVOICES_RECORDS_PATH, - ) - - -def _read( - config_builder: ConfigBuilder, - state: Optional[Dict[str, Any]] = None, - expecting_exception: bool = False -) -> EntrypointOutput: - return read( - SourceHarvest(), - config_builder.build(), - CatalogBuilder().with_stream(_STREAM_NAME, SyncMode.full_refresh).build(), - state, - expecting_exception - ) - - -class InvoicesTest(TestCase): - - def setUp(self) -> None: - self._datetime_start_date = datetime.fromisoformat(_A_START_DATE) - self._string_formatted_start_date = self._datetime_start_date.strftime('%Y-%m-%dT%H:%M:%SZ') - - @HttpMocker() - def test_given_start_date_when_read_then_request_is_created_properly(self, http_mocker: HttpMocker): - http_mocker.get( - HttpRequest( - url="https://api.harvestapp.com/v2/invoices", - query_params={ - "per_page": "50", - "updated_since": self._string_formatted_start_date, - }, - ), - _invoices_response().with_record(_an_invoice().with_id(_AN_INVOICE_ID)).build() - ) - http_mocker.get( - HttpRequest( - url=f"https://api.harvestapp.com/v2/invoices/{_AN_INVOICE_ID}/messages", - query_params={ - "per_page": "50", - "updated_since": self._string_formatted_start_date, - }, - ), - _invoices_response().with_record(_a_message()).build() - ) - - _read(ConfigBuilder().with_account_id(_AN_ACCOUNT_ID).with_api_token(_AN_API_KEY).with_replication_start_date(self._datetime_start_date)) - - # endpoint is called diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/integration/test_invoices.py b/airbyte-integrations/connectors/source-harvest/unit_tests/integration/test_invoices.py deleted file mode 100644 index ff1c1678fd4c..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/integration/test_invoices.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. - -from datetime import datetime -from typing import Any, Dict, Optional -from unittest import TestCase - -from airbyte_cdk.test.catalog_builder import CatalogBuilder -from airbyte_cdk.test.entrypoint_wrapper import EntrypointOutput, read -from airbyte_cdk.test.mock_http import HttpMocker, HttpRequest, HttpResponse -from airbyte_cdk.test.mock_http.response_builder import ( - FieldPath, - HttpResponseBuilder, - RecordBuilder, - create_record_builder, - create_response_builder, - find_template, -) -from airbyte_protocol.models import SyncMode -from config import ConfigBuilder -from source_harvest import SourceHarvest - -_A_START_DATE = "2021-01-01T00:00:00+00:00" -_AN_ACCOUNT_ID = "1209384" -_AN_API_KEY = "harvestapikey" -_STREAM_NAME = "invoices" -_TEMPLATE_NAME = "invoices" -_RECORDS_PATH = FieldPath("invoices") - - -def _an_invoice() -> RecordBuilder: - return create_record_builder( - find_template(_TEMPLATE_NAME, __file__), - _RECORDS_PATH, - ) - - -def _invoices_response() -> HttpResponseBuilder: - return create_response_builder( - find_template(_TEMPLATE_NAME, __file__), - _RECORDS_PATH, - ) - - -def _read( - config_builder: ConfigBuilder, - state: Optional[Dict[str, Any]] = None, - expecting_exception: bool = False -) -> EntrypointOutput: - return read( - SourceHarvest(), - config_builder.build(), - CatalogBuilder().with_stream(_STREAM_NAME, SyncMode.full_refresh).build(), - state, - expecting_exception - ) - - -class InvoicesTest(TestCase): - @HttpMocker() - def test_given_start_date_when_read_then_request_is_created_properly(self, http_mocker: HttpMocker): - - datetime_start_date = datetime.fromisoformat(_A_START_DATE) - string_formatted_start_date = datetime_start_date.strftime('%Y-%m-%dT%H:%M:%SZ') - - http_mocker.get( - HttpRequest( - url="https://api.harvestapp.com/v2/invoices", - query_params={ - "per_page": "50", - "updated_since": string_formatted_start_date, - }, - headers={ - "Authorization": f"Bearer {_AN_API_KEY}", - "Harvest-Account-ID": _AN_ACCOUNT_ID, - } - ), - _invoices_response().build() - ) - - _read(ConfigBuilder().with_account_id(_AN_ACCOUNT_ID).with_api_token(_AN_API_KEY).with_replication_start_date(datetime_start_date)) - - # endpoint is called diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/pagination.py b/airbyte-integrations/connectors/source-harvest/unit_tests/pagination.py deleted file mode 100644 index 351c3c576a3e..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/pagination.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. - -from typing import Any, Dict - -from airbyte_cdk.test.mock_http.response_builder import PaginationStrategy - - -class HarvestPaginationStrategy(PaginationStrategy): - @staticmethod - def update(response: Dict[str, Any]) -> None: - response["links"]["next"] = "https://api.harvestapp.com/v2/invoices?page=2&per_page=50" \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/request_builder.py b/airbyte-integrations/connectors/source-harvest/unit_tests/request_builder.py deleted file mode 100644 index bd38dd0a4701..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/request_builder.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. - -import base64 -from datetime import datetime -from typing import List, Optional - -from airbyte_cdk.test.mock_http import HttpRequest -from airbyte_cdk.test.mock_http.request import ANY_QUERY_PARAMS - - -class HarvestRequestBuilder: - - @classmethod - def invoices_endpoint(cls, account_id: str) -> "HarvestRequestBuilder": - return cls("invoices", account_id) - - @classmethod - def invoice_messages_endpoint(cls, account_id: str, invoice_id: str) -> "HarvestRequestBuilder": - return cls(f"invoices/{invoice_id}/messages", account_id) - - @classmethod - def expenses_clients_endpoint(cls, account_id: str) -> "HarvestRequestBuilder": - return cls("reports/expenses/clients", account_id) - - def __init__(self, resource: str, account_id: str) -> "HarvestRequestBuilder": - self._resource: str = resource - self._account_id: str = account_id - self._per_page: Optional[int] = None - self._page: Optional[int] = None - self._updated_since: Optional[str] = None - self._from: Optional[str] = None - self._to: Optional[str] = None - self._any_query_params: bool = False - - - def with_any_query_params(self) -> "HarvestRequestBuilder": - self._any_query_params = True - return self - - def with_per_page(self, per_page: int) -> "HarvestRequestBuilder": - self._per_page = per_page - return self - - def with_page(self, page: int) -> "HarvestRequestBuilder": - self._page = page - return self - - def with_updated_since(self, updated_since: str) -> "HarvestRequestBuilder": - self._updated_since = updated_since - return self - - def with_from(self, _from: datetime) -> "HarvestRequestBuilder": - self._from = datetime.strftime(_from, "%Y%m%d") - return self - - def with_to(self, to: datetime) -> "HarvestRequestBuilder": - self._to = datetime.strftime(to, "%Y%m%d") - return self - - def build(self) -> HttpRequest: - query_params = {} - if self._page: - query_params["page"] = self._page - if self._per_page: - query_params["per_page"] = self._per_page - if self._updated_since: - query_params["updated_since"] = self._updated_since - if self._from: - query_params["from"] = self._from - if self._to: - query_params["to"] = self._to - - if self._any_query_params: - if query_params: - raise ValueError(f"Both `any_query_params` and {list(query_params.keys())} were configured. Provide only one of none but not both.") - query_params = ANY_QUERY_PARAMS - - return HttpRequest( - url=f"https://api.harvestapp.com/v2/{self._resource}", - query_params=query_params, - headers={} - ) \ No newline at end of file diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/400.json b/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/400.json deleted file mode 100644 index 4ef4f111d37c..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/400.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "code": 400, - "explanation": "Cannot determine what actual 400 response is so this is a placeholder explanation." -} diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/401.json b/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/401.json deleted file mode 100644 index 97870c0f131f..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/401.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "code": 401, - "explanation": "Cannot determine what actual 401 response is so this is a placeholder explanation." -} diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/403.json b/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/403.json deleted file mode 100644 index ff2e4117e6b8..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/403.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "code": 403, - "explanation": "The object you requested was found but you don’t have authorization to perform your request." -} diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/404.json b/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/404.json deleted file mode 100644 index 2d99e509a128..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/404.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "code": 404, - "explanation": "The object you requested can’t be found." -} diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/expenses_clients.json b/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/expenses_clients.json deleted file mode 100644 index 5ccf60e2c4c4..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/expenses_clients.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "results": [ - { - "client_id": 5735776, - "client_name": "123 Industries", - "total_amount": 100, - "billable_amount": 100, - "currency": "EUR" - }, - { - "client_id": 5735774, - "client_name": "ABC Corp", - "total_amount": 133.35, - "billable_amount": 133.35, - "currency": "USD" - } - ], - "per_page": 50, - "total_pages": 1, - "total_entries": 2, - "next_page": null, - "previous_page": null, - "page": 1, - "links": { - "first": null, - "next": null, - "previous": null, - "last": null - } -} diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/invoice_messages.json b/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/invoice_messages.json deleted file mode 100644 index 9bc7cbd4f71a..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/invoice_messages.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "invoice_messages": [ - { - "id": 27835209, - "sent_by": "Bob Powell", - "sent_by_email": "bobpowell@example.com", - "sent_from": "Bob Powell", - "sent_from_email": "bobpowell@example.com", - "include_link_to_client_invoice": false, - "send_me_a_copy": false, - "thank_you": false, - "reminder": false, - "send_reminder_on": null, - "created_at": "2017-08-23T22:15:06Z", - "updated_at": "2017-08-23T22:15:06Z", - "attach_pdf": true, - "event_type": null, - "recipients": [ - { - "name": "Richard Roe", - "email": "richardroe@example.com" - } - ], - "subject": "Past due invoice reminder: #1001 from API Examples", - "body": "Dear Customer,\r\n\r\nThis is a friendly reminder to let you know that Invoice 1001 is 144 days past due. If you have already sent the payment, please disregard this message. If not, we would appreciate your prompt attention to this matter.\r\n\r\nThank you for your business.\r\n\r\nCheers,\r\nAPI Examples" - }, - { - "id": 27835207, - "sent_by": "Bob Powell", - "sent_by_email": "bobpowell@example.com", - "sent_from": "Bob Powell", - "sent_from_email": "bobpowell@example.com", - "include_link_to_client_invoice": false, - "send_me_a_copy": true, - "thank_you": false, - "reminder": false, - "send_reminder_on": null, - "created_at": "2017-08-23T22:14:49Z", - "updated_at": "2017-08-23T22:14:49Z", - "attach_pdf": true, - "event_type": null, - "recipients": [ - { - "name": "Richard Roe", - "email": "richardroe@example.com" - }, - { - "name": "Bob Powell", - "email": "bobpowell@example.com" - } - ], - "subject": "Invoice #1001 from API Examples", - "body": "---------------------------------------------\r\nInvoice Summary\r\n---------------------------------------------\r\nInvoice ID: 1001\r\nIssue Date: 04/01/2017\r\nClient: 123 Industries\r\nP.O. Number: \r\nAmount: €288.90\r\nDue: 04/01/2017 (upon receipt)\r\n\r\nThe detailed invoice is attached as a PDF.\r\n\r\nThank you!\r\n---------------------------------------------" - } - ], - "per_page": 50, - "total_pages": 1, - "total_entries": 2, - "next_page": null, - "previous_page": null, - "page": 1, - "links": { - "first": null, - "next": null, - "previous": null, - "last": null - } -} diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/invoices.json b/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/invoices.json deleted file mode 100644 index da211208d90f..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/resource/http/response/invoices.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "invoices": [ - { - "id": 13150403, - "client_key": "21312da13d457947a217da6775477afee8c2eba8", - "number": "1001", - "purchase_order": "", - "amount": 288.9, - "due_amount": 288.9, - "tax": 5, - "tax_amount": 13.5, - "tax2": 2, - "tax2_amount": 5.4, - "discount": 10, - "discount_amount": 30, - "subject": "Online Store - Phase 1", - "notes": "Some notes about the invoice.", - "state": "open", - "period_start": "2017-03-01", - "period_end": "2017-03-01", - "issue_date": "2017-04-01", - "due_date": "2017-04-01", - "payment_term": "upon receipt", - "sent_at": "2017-08-23T22:25:59Z", - "paid_at": null, - "paid_date": null, - "closed_at": null, - "recurring_invoice_id": null, - "created_at": "2017-06-27T16:27:16Z", - "updated_at": "2017-08-23T22:25:59Z", - "currency": "EUR", - "payment_options": ["credit_card"], - "client": { - "id": 5735776, - "name": "123 Industries" - }, - "estimate": null, - "retainer": null, - "creator": { - "id": 1782884, - "name": "Bob Powell" - }, - "line_items": [ - { - "id": 53341602, - "kind": "Service", - "description": "03/01/2017 - Project Management: [9:00am - 11:00am] Planning meetings", - "quantity": 2, - "unit_price": 100, - "amount": 200, - "taxed": true, - "taxed2": true, - "project": { - "id": 14308069, - "name": "Online Store - Phase 1", - "code": "OS1" - } - }, - { - "id": 53341603, - "kind": "Service", - "description": "03/01/2017 - Programming: [1:00pm - 2:00pm] Importing products", - "quantity": 1, - "unit_price": 100, - "amount": 100, - "taxed": true, - "taxed2": true, - "project": { - "id": 14308069, - "name": "Online Store - Phase 1", - "code": "OS1" - } - } - ] - }, - { - "id": 13150378, - "client_key": "9e97f4a65c5b83b1fc02f54e5a41c9dc7d458542", - "number": "1000", - "purchase_order": "1234", - "amount": 10700.0, - "due_amount": 0.0, - "tax": 5.0, - "tax_amount": 500.0, - "tax2": 2.0, - "tax2_amount": 200.0, - "discount": null, - "discount_amount": 0.0, - "subject": "Online Store - Phase 1", - "notes": "Some notes about the invoice.", - "state": "paid", - "period_start": null, - "period_end": null, - "issue_date": "2017-02-01", - "due_date": "2017-03-03", - "payment_term": "custom", - "sent_at": "2017-02-01T07:00:00Z", - "paid_at": "2017-02-21T00:00:00Z", - "paid_date": "2017-02-21", - "closed_at": null, - "recurring_invoice_id": null, - "created_at": "2017-06-27T16:24:30Z", - "updated_at": "2017-06-27T16:24:57Z", - "currency": "USD", - "client": { - "id": 5735776, - "name": "123 Industries" - }, - "estimate": { - "id": 1439814 - }, - "retainer": null, - "creator": { - "id": 1782884, - "name": "Bob Powell" - }, - "line_items": [ - { - "id": 53341450, - "kind": "Service", - "description": "50% of Phase 1 of the Online Store", - "quantity": 100.0, - "unit_price": 100.0, - "amount": 10000.0, - "taxed": true, - "taxed2": true, - "project": { - "id": 14308069, - "name": "Online Store - Phase 1", - "code": "OS1" - } - } - ] - } - ], - "per_page": 50, - "total_pages": 1, - "total_entries": 2, - "next_page": null, - "previous_page": null, - "page": 1, - "links": { - "first": null, - "next": null, - "previous": null, - "last": null - } -} diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_config.json b/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_config.json deleted file mode 100644 index f0cbd4f67ac6..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "account_id": "", - "start_date": "2021-01-01T00:00:00Z", - "credentials": { "api_token": "" } -} diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_config_migrations.py b/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_config_migrations.py deleted file mode 100644 index d665f3162f5e..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_config_migrations.py +++ /dev/null @@ -1,80 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - - -import json -import os -from typing import Any, Mapping - -import pytest -from airbyte_cdk.models import OrchestratorType, Type -from airbyte_cdk.sources import Source -from source_harvest.config_migrations import MigrateAuthType -from source_harvest.source import SourceHarvest - -# BASE ARGS -CMD = "check" -TEST_TOKEN_CONFIG_PATH = f"{os.path.dirname(__file__)}/test_config.json" -NEW_TEST_TOKEN_CONFIG_PATH = f"{os.path.dirname(__file__)}/test_new_config.json" -TEST_OAUTH_CONFIG_PATH = f"{os.path.dirname(__file__)}/test_config_oauth.json" -NEW_TEST_OAUTH_CONFIG_PATH = f"{os.path.dirname(__file__)}/test_new_config_oauth.json" -SOURCE: Source = SourceHarvest() - -# HELPERS -def load_config(config_path: str) -> Mapping[str, Any]: - with open(config_path, "r") as config: - return json.load(config) - - -def revert_migration(config_path: str) -> None: - with open(config_path, "r") as test_config: - config = json.load(test_config) - config["credentials"].pop("auth_type") - with open(config_path, "w") as updated_config: - config = json.dumps(config) - updated_config.write(config) - - -@pytest.mark.parametrize( - "config_path, expected_auth_type", - [ - (TEST_TOKEN_CONFIG_PATH, "Token"), - (TEST_OAUTH_CONFIG_PATH, "Client"), - ], -) -def test_migrate_config(config_path, expected_auth_type): - - source_input_args = [CMD, "--config", config_path] - - migration_instance = MigrateAuthType - - migration_instance.migrate(source_input_args, SOURCE) - - test_migrated_config = load_config(config_path) - - # Verify migrated property - assert "auth_type" in test_migrated_config["credentials"] - assert test_migrated_config["credentials"]["auth_type"] == expected_auth_type - - # Test CONTROL MESSAGE was emitted) - control_message = migration_instance.message_repository._message_queue[0] - assert control_message.type == Type.CONTROL - assert control_message.control.type == OrchestratorType.CONNECTOR_CONFIG - - revert_migration(config_path) - - -@pytest.mark.parametrize( - "config_path", - [ - NEW_TEST_TOKEN_CONFIG_PATH, - NEW_TEST_OAUTH_CONFIG_PATH, - ], -) -def test_should_not_migrate_new(config_path): - new_config = load_config(config_path) - instance = MigrateAuthType - assert not instance.should_migrate(new_config) - - diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_config_oauth.json b/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_config_oauth.json deleted file mode 100644 index dc68e718ac23..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_config_oauth.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "account_id": "", - "replication_start_date": "2021-01-01T00:00:00Z", - "credentials": { - "client_id": "", - "client_secret": "", - "client_refresh_token": "" - } -} diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_new_config.json b/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_new_config.json deleted file mode 100644 index 9f8b462a425d..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_new_config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "account_id": "", - "start_date": "2021-01-01T00:00:00Z", - "credentials": { - "auth_type": "bearer", - "api_token": "" - } -} diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_new_config_oauth.json b/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_new_config_oauth.json deleted file mode 100644 index 4638e73e9321..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/test_migrations/test_new_config_oauth.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "account_id": "", - "replication_start_date": "2021-01-01T00:00:00Z", - "credentials": { - "auth_type": "Client", - "client_id": "", - "client_secret": "", - "client_refresh_token": "" - } -} diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/test_source.py b/airbyte-integrations/connectors/source-harvest/unit_tests/test_source.py deleted file mode 100644 index 113ff6d5f42b..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/test_source.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. - -import json -import unittest -from unittest.mock import Mock, patch - -import pytest -import requests -from airbyte_cdk import AirbyteLogger -from airbyte_cdk.models import ConfiguredAirbyteCatalog, FailureType, Status, SyncMode -from airbyte_cdk.test.catalog_builder import CatalogBuilder -from airbyte_cdk.test.entrypoint_wrapper import EntrypointOutput, read -from airbyte_cdk.test.mock_http import HttpMocker, HttpRequest, HttpResponse -from airbyte_cdk.test.mock_http.response_builder import find_template -from airbyte_cdk.utils import AirbyteTracedException -from config import ConfigBuilder -from requests import HTTPError -from source_harvest import SourceHarvest - - -def _a_response_with_error_code(status_code: int) -> HttpResponse: - return HttpResponse(json.dumps(find_template(str(status_code), __file__)), status_code) - -def _a_request() -> HttpMocker: - return HttpRequest( - url="https://api.harvestapp.com/v2/company", - query_params="any query_parameters" - ) - -def _catalog() -> ConfiguredAirbyteCatalog: - return CatalogBuilder().with_stream("company", SyncMode.full_refresh).build() - -class SourceTest(unittest.TestCase): - - def setUp(self) -> None: - self._source = SourceHarvest() - self._logger = Mock(spec=AirbyteLogger) - self._config = ConfigBuilder().build() - - def test_given_config_with_client_id_without_account_id_when_check_connection_then_not_available(self) -> None: - config = ConfigBuilder().with_client_id("a client id").build() - config.pop("account_id") - - is_available, error = self._source.check_connection(self._logger, config) - assert not is_available - assert error == "Unable to connect to stream company - Request to https://api.harvestapp.com/v2/company failed with status code 401 and error message invalid_token" - - def test_given_config_no_authentication_in_config_when_check_connection_then_not_available(self) -> None: - config = ConfigBuilder().build() - config["credentials"].pop("api_token", None) - config["credentials"].pop("client_id", None) - - is_available, error = self._source.check_connection(self._logger, config) - assert not is_available - - @HttpMocker() - def test_given_400_http_error_read_then_raises_config_error(self, http_mocker: HttpMocker) -> None: - - http_mocker.get( - _a_request(), - _a_response_with_error_code(400) - ) - - output = read(self._source, self._config, _catalog(), state=None, expecting_exception=True) - assert output.errors[-1].trace.error.failure_type== FailureType.config_error - - @HttpMocker() - def test_given_401_http_error_when_read_then_raises_config_error(self, http_mocker: HttpMocker) -> None: - - http_mocker.get( - _a_request(), - _a_response_with_error_code(401) - ) - output = read(self._source, self._config, _catalog(), state=None, expecting_exception=True) - print(output) - - assert output.errors[-1].trace.error.failure_type== FailureType.config_error - - @HttpMocker() - def test_given_403_http_error_when_read_then_raises_config_error(self, http_mocker: HttpMocker) -> None: - http_mocker.get( - _a_request(), - _a_response_with_error_code(403) - ) - - output = read(self._source, self._config, _catalog(), state=None, expecting_exception=True) - assert output.errors[-1].trace.error.failure_type== FailureType.config_error - - @HttpMocker() - def test_given_404_http_error_when_read_then_raises_config_error(self, http_mocker: HttpMocker) -> None: - http_mocker.get( - _a_request(), - _a_response_with_error_code(404) - ) - - output = read(self._source, self._config, _catalog(), state=None, expecting_exception=True) - assert output.errors[-1].trace.error.failure_type == FailureType.config_error diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/test_streams.py b/airbyte-integrations/connectors/source-harvest/unit_tests/test_streams.py deleted file mode 100644 index e3c75953c74d..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/test_streams.py +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -from airbyte_cdk.logger import init_logger -from airbyte_cdk.models import ConfiguredAirbyteCatalog -from source_harvest.source import SourceHarvest - -logger = init_logger("airbyte") - - -def test_skip_stream_default_availability_strategy(config, requests_mock): - requests_mock.get("https://api.harvestapp.com/v2/estimates", status_code=403, json={"error": "error"}) - catalog = ConfiguredAirbyteCatalog.parse_obj( - { - "streams": [ - { - "stream": { - "name": "estimates", - "json_schema": {}, - "supported_sync_modes": ["full_refresh", "incremental"], - "source_defined_cursor": True, - "default_cursor_field": ["updated_at"], - }, - "sync_mode": "incremental", - "cursor_field": ["updated_at"], - "destination_sync_mode": "append", - } - ] - } - ) - - list(SourceHarvest().read(logger, config, catalog, {})) diff --git a/airbyte-integrations/connectors/source-harvest/unit_tests/unit_test.py b/airbyte-integrations/connectors/source-harvest/unit_tests/unit_test.py deleted file mode 100644 index f5737eea78bc..000000000000 --- a/airbyte-integrations/connectors/source-harvest/unit_tests/unit_test.py +++ /dev/null @@ -1,152 +0,0 @@ -# -# Copyright (c) 2023 Airbyte, Inc., all rights reserved. -# - -import json -from datetime import datetime, timedelta -from unittest import TestCase - -from airbyte_cdk.test.catalog_builder import CatalogBuilder -from airbyte_cdk.test.entrypoint_wrapper import read -from airbyte_cdk.test.mock_http import HttpMocker -from airbyte_cdk.test.mock_http.response_builder import ( - FieldPath, - HttpResponseBuilder, - RecordBuilder, - create_record_builder, - create_response_builder, - find_template, -) -from airbyte_protocol.models import SyncMode -from config import ConfigBuilder -from freezegun import freeze_time -from pagination import HarvestPaginationStrategy -from request_builder import HarvestRequestBuilder -from source_harvest.source import SourceHarvest - - -def _a_record(stream_name: str, data_path: str, primary_key: str) -> RecordBuilder: - return create_record_builder( - find_template(stream_name, __file__), - records_path=FieldPath(data_path), - record_id_path=FieldPath(primary_key), - record_cursor_path=None - ) - -def _a_response(stream_name: str, data_path: str) -> HttpResponseBuilder: - return create_response_builder( - find_template(stream_name, __file__), - records_path=FieldPath(data_path), - pagination_strategy=HarvestPaginationStrategy() - ) - -@freeze_time("2024-03-24") -class UnitTest(TestCase): - - def setUp(self) -> None: - self._config = ConfigBuilder().build() - - def test_streams(self): - streams = SourceHarvest().streams(self._config) - assert len(streams) == 32 - - @HttpMocker() - def test_next_page_token(self, http_mocker: HttpMocker): - - catalog = CatalogBuilder().with_stream("invoices", SyncMode.full_refresh).build() - - stream_name = "invoices" - stream_pk = "id" - - http_mocker.get( - HarvestRequestBuilder.invoices_endpoint("account_id").with_per_page(50).with_updated_since("2021-01-01T00:00:00Z").build(), - _a_response(stream_name="invoices", data_path="invoices").with_record(_a_record(stream_name=stream_name, data_path=stream_name, primary_key=stream_pk)).with_pagination().build() - ) - - http_mocker.get( - HarvestRequestBuilder.invoices_endpoint("account_id").with_page(2).with_per_page(50).with_updated_since("2021-01-01T00:00:00Z").build(), - _a_response(stream_name="invoices", data_path="invoices").with_record(_a_record(stream_name=stream_name, data_path=stream_name, primary_key=stream_pk)).build() - ) - - output = read(SourceHarvest(), config=self._config, catalog=catalog) - len(output.records) == 2 - - @HttpMocker() - def test_child_stream_partitions(self, http_mocker: HttpMocker): - - stream_name = "invoices" - stream_pk = "id" - - http_mocker.get( - HarvestRequestBuilder.invoices_endpoint("account_id").with_any_query_params().build(), - [_a_response(stream_name=stream_name, data_path=stream_name).with_record(_a_record(stream_name=stream_name, data_path=stream_name, primary_key=stream_pk).with_field(FieldPath(stream_pk), 1)).with_record(_a_record(stream_name=stream_name, data_path=stream_name, primary_key=stream_pk).with_field(FieldPath(stream_pk), 2)).build()] - ) - - output_1 = read(SourceHarvest(), config=self._config, catalog=CatalogBuilder().with_stream("invoices", SyncMode.full_refresh).build()) - - invoice_1_id = json.loads(output_1.records[0].json())["record"]["data"]["id"] - invoice_2_id = json.loads(output_1.records[1].json())["record"]["data"]["id"] - - stream_name = "invoice_messages" - - http_mocker.get( - HarvestRequestBuilder.invoice_messages_endpoint("account_id", invoice_1_id).with_any_query_params().build(), - _a_response(stream_name=stream_name, data_path=stream_name).with_record(_a_record(stream_name=stream_name, data_path=stream_name, primary_key=stream_pk)).build() - ) - - http_mocker.get( - HarvestRequestBuilder.invoice_messages_endpoint("account_id", invoice_2_id).with_any_query_params().build(), - _a_response(stream_name=stream_name, data_path=stream_name).with_record(_a_record(stream_name=stream_name, data_path=stream_name, primary_key=stream_pk)).build() - ) - - read(SourceHarvest(), config=self._config, catalog=CatalogBuilder().with_stream("invoice_messages", SyncMode.full_refresh).build()) - # Http Matcher test - - @HttpMocker() - def test_report_based_stream(self, http_mocker: HttpMocker): - - stream_name = "expenses_clients" - stream_pk = "client_id" - data_path = "results" - - http_mocker.get( - HarvestRequestBuilder.expenses_clients_endpoint("account_id").with_any_query_params().build(), - _a_response(stream_name=stream_name, data_path=data_path).with_record(_a_record(stream_name, data_path, stream_pk)).build() - ) - - output = read(SourceHarvest(), config=self._config, catalog=CatalogBuilder().with_stream(stream_name, SyncMode.full_refresh).build()) - - len(output.records) == 1 - - @HttpMocker() - def test_report_based_stream_slices(self, http_mocker: HttpMocker): - - stream_name = "expenses_clients" - stream_pk = "client_id" - data_path = "results" - - replication_start_date = "2021-01-01T00:00:00Z" - replication_start_datetime = datetime.strptime(replication_start_date, "%Y-%m-%dT%H:%M:%SZ") - - config = ConfigBuilder().with_replication_start_date(replication_start_datetime).build() - - while replication_start_datetime < datetime.now(): - - # Adds 364 days to create a 365-day-long duration, which is max for Harvest API - if replication_start_datetime + timedelta(days=364) < datetime.now(): - end_datetime = replication_start_datetime + timedelta(days=364) - else: - end_datetime = datetime.now() - - end_datetime = replication_start_datetime + timedelta(days=364) if replication_start_datetime + timedelta(days=364) < datetime.now() else datetime.now() - - http_mocker.get( - HarvestRequestBuilder.expenses_clients_endpoint("account_id").with_per_page(50).with_from(replication_start_datetime).with_to(end_datetime).build(), - _a_response(stream_name=stream_name, data_path=data_path).with_record(_a_record(stream_name, data_path, stream_pk)).build() - ) - - replication_start_datetime = end_datetime + timedelta(days=1) - - output = read(SourceHarvest(), config=config, catalog=CatalogBuilder().with_stream(stream_name, SyncMode.full_refresh).build()) - - assert len(output.records) == 4 \ No newline at end of file diff --git a/docs/integrations/sources/harvest.md b/docs/integrations/sources/harvest.md index 71b4c2b57353..ce9ac879ae6b 100644 --- a/docs/integrations/sources/harvest.md +++ b/docs/integrations/sources/harvest.md @@ -91,6 +91,7 @@ The connector is restricted by the [Harvest rate limits](https://help.getharvest | Version | Date | Pull Request | Subject | |:--------| :--------- | :------------------------------------------------------- |:----------------------------------------------------------------------------------------------------------------------------------| +| 1.1.0-rc1 | 2024-10-09 | [46685](https://github.com/airbytehq/airbyte/pull/46685) | Migrate to Manifest-only | | 1.0.19 | 2024-10-05 | [46470](https://github.com/airbytehq/airbyte/pull/46470) | Update dependencies | | 1.0.18 | 2024-09-28 | [46143](https://github.com/airbytehq/airbyte/pull/46143) | Update dependencies | | 1.0.17 | 2024-09-21 | [45835](https://github.com/airbytehq/airbyte/pull/45835) | Update dependencies |