From 737d83a5d76bfcc0e06e2be6a90ca50563429f3d Mon Sep 17 00:00:00 2001 From: Max Inno <40697586+innomaxx@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:42:03 +0300 Subject: [PATCH] feat(api): Reports API changes (#109) --- crowdin_api/api_resources/reports/enums.py | 14 + .../requests/cost_estimation_post_editing.py | 15 + .../group_translation_costs_post_editing.py | 17 + .../translation_costs_post_editing.py | 16 + crowdin_api/api_resources/reports/resource.py | 319 ++++++++++++ .../reports/tests/test_reports_resources.py | 468 ++++++++++++++++++ crowdin_api/api_resources/reports/types.py | 13 +- requirements/requirements.txt | 1 + setup.py | 1 + 9 files changed, 863 insertions(+), 1 deletion(-) create mode 100644 crowdin_api/api_resources/reports/requests/cost_estimation_post_editing.py create mode 100644 crowdin_api/api_resources/reports/requests/group_translation_costs_post_editing.py create mode 100644 crowdin_api/api_resources/reports/requests/translation_costs_post_editing.py diff --git a/crowdin_api/api_resources/reports/enums.py b/crowdin_api/api_resources/reports/enums.py index 8531057..f9450f0 100644 --- a/crowdin_api/api_resources/reports/enums.py +++ b/crowdin_api/api_resources/reports/enums.py @@ -6,6 +6,8 @@ class ReportName(Enum): TRANSLATION_COSTS = "translation-costs" TOP_MEMBERS = "top-members" CONTRIBUTION_RAW_DATA = "contribution-raw-data" + COSTS_ESTIMATION_POST_EDITING = "costs-estimation-pe" + TRANSLATION_COSTS_POST_EDITING = "translation-costs-pe" class Unit(Enum): @@ -84,3 +86,15 @@ class ReportSettingsTemplatesPatchPath(Enum): UNIT = "unit" MODE = "mode" CONFIG = "config" + + +class ReportLabelIncludeType(Enum): + STRINGS_WITH_LABEL = "strings_with_label" + STRINGS_WITHOUT_LABEL = "strings_without_label" + + +class MatchType(Enum): + PERFECT = "perfect" + OPTION_100 = "100" + OPTION_99_82 = "99-82" + OPTION_81_60 = "81-60" diff --git a/crowdin_api/api_resources/reports/requests/cost_estimation_post_editing.py b/crowdin_api/api_resources/reports/requests/cost_estimation_post_editing.py new file mode 100644 index 0000000..5373d8b --- /dev/null +++ b/crowdin_api/api_resources/reports/requests/cost_estimation_post_editing.py @@ -0,0 +1,15 @@ +from typing import Iterable + +from crowdin_api.api_resources.reports.types import Match +from crowdin_api.typing import TypedDict + + +class IndividualRate(TypedDict): + languageIds: Iterable[str] + userIds: Iterable[int] + fullTranslation: float + proofread: float + + +class NetRateSchemes(TypedDict): + tmMatch: Iterable[Match] diff --git a/crowdin_api/api_resources/reports/requests/group_translation_costs_post_editing.py b/crowdin_api/api_resources/reports/requests/group_translation_costs_post_editing.py new file mode 100644 index 0000000..50612ae --- /dev/null +++ b/crowdin_api/api_resources/reports/requests/group_translation_costs_post_editing.py @@ -0,0 +1,17 @@ +from typing import Iterable + +from crowdin_api.api_resources.reports.types import Match +from crowdin_api.typing import TypedDict + + +class IndividualRate(TypedDict): + languageIds: Iterable[str] + userIds: Iterable[int] + fullTranslation: float + proofread: float + + +class NetRateSchemes(TypedDict): + tmMatch: Iterable[Match] + mtMatch: Iterable[Match] + suggestionMatch: Iterable[Match] diff --git a/crowdin_api/api_resources/reports/requests/translation_costs_post_editing.py b/crowdin_api/api_resources/reports/requests/translation_costs_post_editing.py new file mode 100644 index 0000000..268b338 --- /dev/null +++ b/crowdin_api/api_resources/reports/requests/translation_costs_post_editing.py @@ -0,0 +1,16 @@ +from typing import Iterable +from crowdin_api.api_resources.reports.types import Match +from crowdin_api.typing import TypedDict + + +class IndividualRate(TypedDict): + languageIds: Iterable[str] + userIds: Iterable[int] + fullTranslation: float + proofread: float + + +class NetRateSchemes(TypedDict): + tmMatch: Iterable[Match] + mtMatch: Iterable[Match] + suggestionMatch: Iterable[Match] diff --git a/crowdin_api/api_resources/reports/resource.py b/crowdin_api/api_resources/reports/resource.py index aabcbe2..11a5794 100644 --- a/crowdin_api/api_resources/reports/resource.py +++ b/crowdin_api/api_resources/reports/resource.py @@ -1,6 +1,7 @@ import abc from datetime import datetime from typing import Dict, Iterable, Optional +from deprecated import deprecated from crowdin_api.api_resources.abstract.resources import BaseResource from crowdin_api.api_resources.reports.enums import ( @@ -9,6 +10,15 @@ Format, GroupBy, Unit, + ReportLabelIncludeType, +) +from crowdin_api.api_resources.reports.requests.cost_estimation_post_editing import ( + IndividualRate as CostEstimationPeIndividualRate, + NetRateSchemes as CostEstimationPeNetRateSchemes +) +from crowdin_api.api_resources.reports.requests.translation_costs_post_editing import ( + IndividualRate as TranslationCostsPeIndividualRate, + NetRateSchemes as TranslationCostsPeNetRateSchemes ) from crowdin_api.api_resources.reports.types import ( FuzzyIndividualRate, @@ -18,6 +28,7 @@ StepTypes, ReportSettingsTemplatesPatchRequest, Config, + BaseRates ) @@ -46,18 +57,22 @@ def generate_report(self, projectId: int, request_data: Dict): ) @abc.abstractmethod + @deprecated("Use other methods instead") def generate_simple_cost_estimate_report(self, projectId: int, **kwargs): raise NotImplementedError("Not implemented") @abc.abstractmethod + @deprecated("Use other methods instead") def generate_fuzzy_cost_estimate_report(self, projectId: int, **kwargs): raise NotImplementedError("Not implemented") @abc.abstractmethod + @deprecated("Use other methods instead") def generate_simple_translation_cost_report(self, projectId: int, **kwargs): raise NotImplementedError("Not implemented") @abc.abstractmethod + @deprecated("Use other methods instead") def generate_fuzzy_translation_cost_report(self, projectId: int, **kwargs): raise NotImplementedError("Not implemented") @@ -128,6 +143,190 @@ def generate_contribution_raw_data_report( }, ) + def generate_costs_estimation_post_editing_general_report( + self, + project_id: int, + base_rates: BaseRates, + individual_rates: Iterable[CostEstimationPeIndividualRate], + net_rate_schemes: CostEstimationPeNetRateSchemes, + unit: Optional[Unit] = None, + currency: Optional[Currency] = None, + format: Optional[Format] = None, + calculate_internal_matches: Optional[bool] = None, + include_pre_translated_strings: Optional[bool] = None, + language_id: Optional[str] = None, + file_ids: Optional[Iterable[int]] = None, + directory_ids: Optional[Iterable[int]] = None, + branch_ids: Optional[Iterable[int]] = None, + date_from: Optional[datetime] = None, + date_to: Optional[datetime] = None, + label_ids: Optional[Iterable[int]] = None, + label_include_type: Optional[ReportLabelIncludeType] = None + ): + """ + Generate Report. + + Link to documentation: + https://developer.crowdin.com/api/v2/#operation/api.projects.reports.post + + Link to documentation for enterprise: + https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post + """ + + return self.generate_report( + projectId=project_id, + request_data={ + "name": "costs-estimation-pe", + "schema": { + "unit": unit, + "currency": currency, + "format": format, + "baseRates": base_rates, + "individualRates": individual_rates, + "netRateSchemes": net_rate_schemes, + "calculateInternalMatches": calculate_internal_matches, + "includePreTranslatedStrings": include_pre_translated_strings, + "languageId": language_id, + "fileIds": file_ids, + "directoryIds": directory_ids, + "branchIds": branch_ids, + "dateFrom": date_from, + "dateTo": date_to, + "labelIds": label_ids, + "labelIncludeType": label_include_type + } + } + ) + + def generate_costs_estimation_post_editing_by_task_report( + self, + project_id: int, + unit: Optional[Unit] = None, + currency: Optional[Currency] = None, + format: Optional[Format] = None, + base_rates: Optional[BaseRates] = None, + individual_rates: Optional[Iterable[CostEstimationPeIndividualRate]] = None, + net_rate_schemes: Optional[CostEstimationPeNetRateSchemes] = None, + calculate_internal_matches: Optional[bool] = None, + include_pre_translated_strings: Optional[bool] = None, + task_id: Optional[int] = None + ): + """ + Generate Report. + + Link to documentation: + https://developer.crowdin.com/api/v2/#operation/api.projects.reports.post + + Link to documentation for enterprise: + https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post + """ + + return self.generate_report( + projectId=project_id, + request_data={ + "name": "costs-estimation-pe", + "schema": { + "unit": unit, + "currency": currency, + "format": format, + "baseRates": base_rates, + "individualRates": individual_rates, + "netRateSchemes": net_rate_schemes, + "calculateInternalMatches": calculate_internal_matches, + "includePreTranslatedStrings": include_pre_translated_strings, + "taskId": task_id + } + } + ) + + def generate_translation_costs_post_editing_general_report( + self, + project_id: int, + base_rates: BaseRates, + individual_rates: Iterable[CostEstimationPeIndividualRate], + net_rate_schemes: CostEstimationPeNetRateSchemes, + unit: Optional[Unit] = None, + currency: Optional[Currency] = None, + format: Optional[Format] = None, + group_by: Optional[GroupBy] = None, + date_from: Optional[datetime] = None, + date_to: Optional[datetime] = None, + language_id: Optional[str] = None, + user_ids: Optional[Iterable[int]] = None, + file_ids: Optional[Iterable[int]] = None, + directory_ids: Optional[Iterable[int]] = None, + branch_ids: Optional[Iterable[int]] = None + ): + """ + Generate Report. + + Link to documentation: + https://developer.crowdin.com/api/v2/#operation/api.projects.reports.post + + Link to documentation for enterprise: + https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post + """ + + return self.generate_report( + projectId=project_id, + request_data={ + "name": "translation-costs-pe", + "schema": { + "unit": unit, + "currency": currency, + "format": format, + "baseRates": base_rates, + "individualRates": individual_rates, + "netRateSchemes": net_rate_schemes, + "groupBy": group_by, + "dateFrom": date_from, + "dateTo": date_to, + "languageId": language_id, + "userIds": user_ids, + "fileIds": file_ids, + "directoryIds": directory_ids, + "branchIds": branch_ids + } + } + ) + + def generate_translation_costs_post_editing_by_task_report( + self, + project_id: int, + base_rates: BaseRates, + individual_rates: Iterable[CostEstimationPeIndividualRate], + net_rate_schemes: CostEstimationPeNetRateSchemes, + unit: Optional[Unit] = None, + currency: Optional[Currency] = None, + format: Optional[Format] = None, + task_id: Optional[int] = None + ): + """ + Generate Report. + + Link to documentation: + https://developer.crowdin.com/api/v2/#operation/api.projects.reports.post + + Link to documentation for enterprise: + https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post + """ + + return self.generate_report( + projectId=project_id, + request_data={ + "name": "translation-costs-pe", + "schema": { + "unit": unit, + "currency": currency, + "format": format, + "baseRates": base_rates, + "individualRates": individual_rates, + "netRateSchemes": net_rate_schemes, + "taskId": task_id + } + } + ) + def check_report_generation_status(self, projectId: int, reportId: str): """ Check Report Generation Status. @@ -313,6 +512,7 @@ class ReportsResource(BaseReportsResource, BaseReportSettingsTemplatesResource): https://developer.crowdin.com/api/v2/#tag/Reports """ + @deprecated("Use other methods instead") def generate_simple_cost_estimate_report( self, projectId: int, @@ -353,6 +553,7 @@ def generate_simple_cost_estimate_report( }, ) + @deprecated("Use other methods instead") def generate_fuzzy_cost_estimate_report( self, projectId: int, @@ -395,6 +596,7 @@ def generate_fuzzy_cost_estimate_report( }, ) + @deprecated("Use other methods instead") def generate_simple_translation_cost_report( self, projectId: int, @@ -432,6 +634,7 @@ def generate_simple_translation_cost_report( }, ) + @deprecated("Use other methods instead") def generate_fuzzy_translation_cost_report( self, projectId: int, @@ -493,6 +696,7 @@ def _prepare_stepTypes(step_types_const: dict, stepTypes: Optional[Iterable[Step return stepTypes + @deprecated("Use other methods instead") def generate_simple_cost_estimate_report( self, projectId: int, @@ -535,6 +739,7 @@ def generate_simple_cost_estimate_report( }, ) + @deprecated("Use other methods instead") def generate_fuzzy_cost_estimate_report( self, projectId: int, @@ -578,6 +783,7 @@ def generate_fuzzy_cost_estimate_report( } ) + @deprecated("Use other methods instead") def generate_simple_translation_cost_report( self, projectId: int, @@ -617,6 +823,7 @@ def generate_simple_translation_cost_report( }, ) + @deprecated("Use other methods instead") def generate_fuzzy_translation_cost_report( self, projectId: int, @@ -655,3 +862,115 @@ def generate_fuzzy_translation_cost_report( }, }, ) + + @staticmethod + def get_group_reports_path(group_id: int, report_id: Optional[str] = None): + if report_id is not None: + return f"groups/{group_id}/reports/{group_id}" + + return f"groups/{group_id}/reports" + + def generate_group_report(self, group_id: int, request_data: Dict): + """ + Generate Group Report. + + Link to documentation for enterprise: + https://developer.crowdin.com/enterprise/api/v2/#operation/api.groups.reports.post + """ + + return self.requester.request( + method="post", + path=self.get_group_reports_path(group_id=group_id), + request_data=request_data, + ) + + def generate_group_translation_costs_post_editing_general_report( + self, + group_id: int, + base_rates: BaseRates, + individual_rates: Iterable[TranslationCostsPeIndividualRate], + net_rate_schemes: TranslationCostsPeNetRateSchemes, + project_ids: Optional[Iterable[int]] = None, + unit: Optional[Unit] = None, + currency: Optional[Currency] = None, + format: Optional[Format] = None, + group_by: Optional[GroupBy] = None, + date_from: Optional[datetime] = None, + date_to: Optional[datetime] = None, + user_ids: Optional[Iterable[int]] = None + ): + """ + Generate Group Report (General). + + Link to documentation: + https://developer.crowdin.com/enterprise/api/v2/#operation/api.groups.reports.post + """ + + return self.generate_group_report( + group_id=group_id, + request_data={ + "name": "group-translation-costs-pe", + "schema": { + "projectIds": project_ids, + "unit": unit, + "currency": currency, + "format": format, + "baseRates": base_rates, + "individualRates": individual_rates, + "netRateSchemes": net_rate_schemes, + "groupBy": group_by, + "dateFrom": date_from, + "dateTo": date_to, + "userIds": user_ids + }, + }, + ) + + @staticmethod + def get_organization_reports_path(report_id: Optional[str] = None): + if report_id is not None: + return f"reports/{report_id}" + + return "reports" + + def generate_organization_translation_costs_post_editing_general_report( + self, + base_rates: BaseRates, + individual_rates: Iterable[TranslationCostsPeIndividualRate], + net_rate_schemes: TranslationCostsPeNetRateSchemes, + project_ids: Optional[Iterable[int]] = None, + unit: Optional[Unit] = None, + currency: Optional[Currency] = None, + format: Optional[Format] = None, + group_by: Optional[GroupBy] = None, + date_from: Optional[datetime] = None, + date_to: Optional[datetime] = None, + user_ids: Optional[Iterable[int]] = None + ): + """ + Generate Organization Report (General). + + Link to documentation: + https://developer.crowdin.com/enterprise/api/v2/#operation/api.reports.post + """ + + return self.requester.request( + method="post", + path=self.get_organization_reports_path(), + request_data={ + "name": "group-translation-costs-pe", + "schema": { + "projectIds": project_ids, + "unit": unit, + "currency": currency, + "format": format, + "baseRates": base_rates, + "individualRates": individual_rates, + "netRateSchemes": net_rate_schemes, + "groupBy": group_by, + "dateFrom": date_from, + "dateTo": date_to, + "userIds": user_ids + }, + }, + ) diff --git a/crowdin_api/api_resources/reports/tests/test_reports_resources.py b/crowdin_api/api_resources/reports/tests/test_reports_resources.py index 88bd95e..5a48482 100644 --- a/crowdin_api/api_resources/reports/tests/test_reports_resources.py +++ b/crowdin_api/api_resources/reports/tests/test_reports_resources.py @@ -12,12 +12,23 @@ SimpleRateMode, Unit, ReportSettingsTemplatesPatchPath, + MatchType, + ReportLabelIncludeType +) +from crowdin_api.api_resources.reports.requests.cost_estimation_post_editing import ( + IndividualRate, + NetRateSchemes +) +from crowdin_api.api_resources.reports.requests.group_translation_costs_post_editing import ( + IndividualRate as GroupIndividualRate, + NetRateSchemes as GroupNetRateSchemes ) from crowdin_api.api_resources.reports.resource import ( ReportsResource, EnterpriseReportsResource, BaseReportSettingsTemplatesResource, ) +from crowdin_api.api_resources.reports.types import BaseRates, Match from crowdin_api.requester import APIRequester @@ -427,6 +438,284 @@ def test_generate_contribution_raw_data_report( request_data={"name": "contribution-raw-data", "schema": schema}, ) + @pytest.mark.parametrize( + "in_params, schema", + [ + ( + { + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "base_rates": BaseRates(fullTranslation=0, proofread=0), + "individual_rates": [ + IndividualRate(languageIds=["uk"], userIds=[1], fullTranslation=0.1, proofread=0.1) + ], + "net_rate_schemes": NetRateSchemes(tmMatch=[ + Match(matchType=MatchType.OPTION_100, price=70) + ]), + "calculate_internal_matches": True, + "include_pre_translated_strings": True, + "language_id": "uk", + "file_ids": [1, 2], + "directory_ids": [1, 2], + "branch_ids": [1, 2], + "date_from": datetime(year=1988, month=1, day=4), + "date_to": datetime(year=2015, month=10, day=13), + "label_ids": [1], + "label_include_type": ReportLabelIncludeType.STRINGS_WITH_LABEL + }, + { + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "baseRates": { + "fullTranslation": 0, + "proofread": 0 + }, + "individualRates": [ + { + "languageIds": ["uk"], + "userIds": [1], + "fullTranslation": 0.1, + "proofread": 0.1 + } + ], + "netRateSchemes": { + "tmMatch": [ + { + "matchType": MatchType.OPTION_100, + "price": 70 + } + ] + }, + "calculateInternalMatches": True, + "includePreTranslatedStrings": True, + "languageId": "uk", + "fileIds": [1, 2], + "directoryIds": [1, 2], + "branchIds": [1, 2], + "dateFrom": datetime(year=1988, month=1, day=4), + "dateTo": datetime(year=2015, month=10, day=13), + "labelIds": [1], + "labelIncludeType": ReportLabelIncludeType.STRINGS_WITH_LABEL + } + ) + ] + ) + @mock.patch("crowdin_api.api_resources.reports.resource.ReportsResource.generate_report") + def test_generate_costs_estimation_post_editing_general_report( + self, m_generate_report, in_params, schema, base_absolut_url + ): + m_generate_report.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert ( + resource.generate_costs_estimation_post_editing_general_report( + project_id=1, + **in_params + ) == "response" + ) + m_generate_report.assert_called_once_with( + projectId=1, + request_data={ + "name": "costs-estimation-pe", + "schema": schema + } + ) + + @pytest.mark.parametrize( + "in_params, schema", + [ + ( + { + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "base_rates": BaseRates(fullTranslation=0, proofread=0), + "individual_rates": [ + IndividualRate(languageIds=["uk"], userIds=[1], fullTranslation=0.1, proofread=0.1) + ], + "net_rate_schemes": NetRateSchemes(tmMatch=[ + Match(matchType=MatchType.OPTION_100, price=70) + ]), + "calculate_internal_matches": True, + "include_pre_translated_strings": True, + "task_id": 1 + }, + { + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "baseRates": { + "fullTranslation": 0, + "proofread": 0 + }, + "individualRates": [ + { + "languageIds": ["uk"], + "userIds": [1], + "fullTranslation": 0.1, + "proofread": 0.1 + } + ], + "netRateSchemes": { + "tmMatch": [ + { + "matchType": MatchType.OPTION_100, + "price": 70 + } + ] + }, + "calculateInternalMatches": True, + "includePreTranslatedStrings": True, + "taskId": 1 + } + ) + ] + ) + @mock.patch("crowdin_api.api_resources.reports.resource.ReportsResource.generate_report") + def test_generate_costs_estimation_post_editing_by_task_report( + self, m_generate_report, in_params, schema, base_absolut_url + ): + m_generate_report.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert ( + resource.generate_costs_estimation_post_editing_by_task_report( + project_id=1, + **in_params + ) == "response" + ) + m_generate_report.assert_called_once_with( + projectId=1, + request_data={ + "name": "costs-estimation-pe", + "schema": schema + } + ) + + @pytest.mark.parametrize( + "in_params, schema", + [ + ( + { + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "base_rates": BaseRates(fullTranslation=0, proofread=0), + "individual_rates": [ + IndividualRate(languageIds=["uk"], userIds=[1], fullTranslation=0.1, proofread=0.1) + ], + "net_rate_schemes": NetRateSchemes(tmMatch=[ + Match(matchType=MatchType.OPTION_99_82, price=70) + ]), + "group_by": GroupBy.LANGUAGE, + "date_from": datetime(year=1988, month=1, day=4), + "date_to": datetime(year=2015, month=10, day=13), + "language_id": "uk", + "user_ids": [1], + "file_ids": [1], + "directory_ids": [1], + "branch_ids": [1] + }, + { + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "baseRates": BaseRates(fullTranslation=0, proofread=0), + "individualRates": [ + IndividualRate(languageIds=["uk"], userIds=[1], fullTranslation=0.1, proofread=0.1) + ], + "netRateSchemes": NetRateSchemes(tmMatch=[ + Match(matchType=MatchType.OPTION_99_82, price=70) + ]), + "groupBy": GroupBy.LANGUAGE, + "dateFrom": datetime(year=1988, month=1, day=4), + "dateTo": datetime(year=2015, month=10, day=13), + "languageId": "uk", + "userIds": [1], + "fileIds": [1], + "directoryIds": [1], + "branchIds": [1] + } + ) + ] + ) + @mock.patch("crowdin_api.api_resources.reports.resource.ReportsResource.generate_report") + def test_generate_translation_costs_post_editing_general_report( + self, m_generate_report, in_params, schema, base_absolut_url + ): + m_generate_report.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert ( + resource.generate_translation_costs_post_editing_general_report( + project_id=1, + **in_params + ) == "response" + ) + m_generate_report.assert_called_once_with( + projectId=1, + request_data={ + "name": "translation-costs-pe", + "schema": schema + } + ) + + @pytest.mark.parametrize( + "in_params, schema", + [ + ( + { + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "base_rates": BaseRates(fullTranslation=0, proofread=0), + "individual_rates": [ + IndividualRate(languageIds=["uk"], userIds=[1], fullTranslation=0.1, proofread=0.1) + ], + "net_rate_schemes": NetRateSchemes(tmMatch=[ + Match(matchType=MatchType.OPTION_99_82, price=70) + ]), + "task_id": 1 + }, + { + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "baseRates": BaseRates(fullTranslation=0, proofread=0), + "individualRates": [ + IndividualRate(languageIds=["uk"], userIds=[1], fullTranslation=0.1, proofread=0.1) + ], + "netRateSchemes": NetRateSchemes(tmMatch=[ + Match(matchType=MatchType.OPTION_99_82, price=70) + ]), + "taskId": 1 + } + ) + ] + ) + @mock.patch("crowdin_api.api_resources.reports.resource.ReportsResource.generate_report") + def test_generate_translation_costs_post_editing_by_task_report( + self, m_generate_report, in_params, schema, base_absolut_url + ): + m_generate_report.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert ( + resource.generate_translation_costs_post_editing_by_task_report( + project_id=1, + **in_params + ) == "response" + ) + m_generate_report.assert_called_once_with( + projectId=1, + request_data={ + "name": "translation-costs-pe", + "schema": schema + } + ) + @mock.patch("crowdin_api.requester.APIRequester.request") def test_check_report_generation_status(self, m_request, base_absolut_url): m_request.return_value = "response" @@ -923,6 +1212,185 @@ def test_generate_contribution_raw_data_report( request_data={"name": "contribution-raw-data", "schema": schema}, ) + @pytest.mark.parametrize( + "in_params, schema", + [ + ( + { + "project_ids": [1, 2, 3], + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "base_rates": BaseRates(fullTranslation=0, proofread=0), + "individual_rates": [ + GroupIndividualRate(languageIds=["uk"], userIds=[1], fullTranslation=0.1, proofread=0.1) + ], + "net_rate_schemes": GroupNetRateSchemes( + tmMatch=[ + Match(matchType=MatchType.OPTION_100, price=70) + ], + mtMatch=[ + Match(matchType=MatchType.OPTION_99_82, price=50) + ], + suggestionMatch=[ + Match(matchType=MatchType.OPTION_81_60, price=30) + ] + ), + "group_by": GroupBy.LANGUAGE, + "date_from": None, + "date_to": None, + "user_ids": [10, 11] + }, + { + "projectIds": [1, 2, 3], + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "baseRates": { + "fullTranslation": 0, + "proofread": 0 + }, + "individualRates": [ + { + "languageIds": ["uk"], + "userIds": [1], + "fullTranslation": 0.1, + "proofread": 0.1 + } + ], + "netRateSchemes": { + "tmMatch": [ + { + "matchType": MatchType.OPTION_100, + "price": 70 + } + ], + "mtMatch": [ + { + "matchType": MatchType.OPTION_99_82, + "price": 50 + } + ], + "suggestionMatch": [ + { + "matchType": MatchType.OPTION_81_60, + "price": 30 + } + ] + }, + "groupBy": GroupBy.LANGUAGE, + "dateFrom": None, + "dateTo": None, + "userIds": [10, 11] + } + ) + ] + ) + @mock.patch("crowdin_api.api_resources.reports.resource.EnterpriseReportsResource.generate_group_report") + def test_generate_group_translation_costs_post_editing_general_report( + self, m_generate_report, in_params, schema, base_absolut_url + ): + m_generate_report.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert ( + resource.generate_group_translation_costs_post_editing_general_report(group_id=1, **in_params) == "response" + ) + m_generate_report.assert_called_once_with( + group_id=1, + request_data={"name": "group-translation-costs-pe", "schema": schema}, + ) + + @pytest.mark.parametrize( + "in_params, schema", + [ + ( + { + "project_ids": [1, 2, 3], + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "base_rates": BaseRates(fullTranslation=0, proofread=0), + "individual_rates": [ + GroupIndividualRate(languageIds=["uk"], userIds=[1], fullTranslation=0.1, proofread=0.1) + ], + "net_rate_schemes": GroupNetRateSchemes( + tmMatch=[ + Match(matchType=MatchType.OPTION_100, price=70) + ], + mtMatch=[ + Match(matchType=MatchType.OPTION_99_82, price=50) + ], + suggestionMatch=[ + Match(matchType=MatchType.OPTION_81_60, price=30) + ] + ), + "group_by": GroupBy.LANGUAGE, + "date_from": None, + "date_to": None, + "user_ids": [10, 11] + }, + { + "projectIds": [1, 2, 3], + "unit": Unit.WORDS, + "currency": Currency.UAH, + "format": Format.XLSX, + "baseRates": { + "fullTranslation": 0, + "proofread": 0 + }, + "individualRates": [ + { + "languageIds": ["uk"], + "userIds": [1], + "fullTranslation": 0.1, + "proofread": 0.1 + } + ], + "netRateSchemes": { + "tmMatch": [ + { + "matchType": MatchType.OPTION_100, + "price": 70 + } + ], + "mtMatch": [ + { + "matchType": MatchType.OPTION_99_82, + "price": 50 + } + ], + "suggestionMatch": [ + { + "matchType": MatchType.OPTION_81_60, + "price": 30 + } + ] + }, + "groupBy": GroupBy.LANGUAGE, + "dateFrom": None, + "dateTo": None, + "userIds": [10, 11] + } + ) + ] + ) + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_generate_organization_translation_costs_post_editing_general_report( + self, m_generate_report, in_params, schema, base_absolut_url + ): + m_generate_report.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert ( + resource.generate_organization_translation_costs_post_editing_general_report(**in_params) == "response" + ) + m_generate_report.assert_called_once_with( + method="post", + path="reports", + request_data={"name": "group-translation-costs-pe", "schema": schema}, + ) + @mock.patch("crowdin_api.requester.APIRequester.request") def test_check_report_generation_status(self, m_request, base_absolut_url): m_request.return_value = "response" diff --git a/crowdin_api/api_resources/reports/types.py b/crowdin_api/api_resources/reports/types.py index 0969cb6..9b9e170 100644 --- a/crowdin_api/api_resources/reports/types.py +++ b/crowdin_api/api_resources/reports/types.py @@ -4,7 +4,8 @@ from crowdin_api.api_resources.reports.enums import ( FuzzyRateMode, SimpleRateMode, - ReportSettingsTemplatesPatchPath + ReportSettingsTemplatesPatchPath, + MatchType ) from crowdin_api.typing import TypedDict @@ -51,3 +52,13 @@ class ReportSettingsTemplatesPatchRequest(TypedDict): value: Union[str, int] op: PatchOperation path: ReportSettingsTemplatesPatchPath + + +class Match(TypedDict): + matchType: MatchType + price: float + + +class BaseRates(TypedDict): + fullTranslation: float + proofread: float diff --git a/requirements/requirements.txt b/requirements/requirements.txt index ff0aec2..8a4c7a6 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -2,3 +2,4 @@ wheel setuptools requests>=2.25.1 +deprecated \ No newline at end of file diff --git a/setup.py b/setup.py index b37b1a0..98108b5 100644 --- a/setup.py +++ b/setup.py @@ -54,6 +54,7 @@ def get_version(): install_requires=[ "requests>=2.25.1", "typing-extensions; python_version < '3.8.0'", + "deprecated" ], classifiers=[ "Programming Language :: Python",