From 27712567e2ad620d2210eb9137db85bb8d89a98f Mon Sep 17 00:00:00 2001 From: Bohdan Bobko <172895427+bhdnb@users.noreply.github.com> Date: Thu, 19 Mar 2026 17:54:27 +0200 Subject: [PATCH 1/2] feat: added User Report Settings Templates support (#208) --- src/CrowdinApiClient/Api/UserApi.php | 92 +++++ .../Model/HourlyBaseRates.php | 40 ++ .../Model/HourlyIndividualRates.php | 112 ++++++ .../HourlyReportSettingsTemplateConfig.php | 81 ++++ .../Model/IndividualRates.php | 2 +- src/CrowdinApiClient/Model/Report.php | 2 + .../Model/ReportSettingsTemplateConfig.php | 73 ++++ .../Model/UserReportSettingsTemplate.php | 158 ++++++++ tests/CrowdinApiClient/Api/UserApiTest.php | 362 +++++++++++++++++- .../Model/HourlyBaseRatesTest.php | 35 ++ .../Model/HourlyIndividualRatesTest.php | 107 ++++++ ...HourlyReportSettingsTemplateConfigTest.php | 106 +++++ .../ReportSettingsTemplateConfigTest.php | 86 +++-- .../Model/ReportSettingsTemplateTest.php | 27 +- .../Model/UserReportSettingsTemplateTest.php | 160 ++++++++ 15 files changed, 1400 insertions(+), 43 deletions(-) create mode 100644 src/CrowdinApiClient/Model/HourlyBaseRates.php create mode 100644 src/CrowdinApiClient/Model/HourlyIndividualRates.php create mode 100644 src/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfig.php create mode 100644 src/CrowdinApiClient/Model/UserReportSettingsTemplate.php create mode 100644 tests/CrowdinApiClient/Model/HourlyBaseRatesTest.php create mode 100644 tests/CrowdinApiClient/Model/HourlyIndividualRatesTest.php create mode 100644 tests/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfigTest.php create mode 100644 tests/CrowdinApiClient/Model/UserReportSettingsTemplateTest.php diff --git a/src/CrowdinApiClient/Api/UserApi.php b/src/CrowdinApiClient/Api/UserApi.php index 4a7f5643..507273ab 100644 --- a/src/CrowdinApiClient/Api/UserApi.php +++ b/src/CrowdinApiClient/Api/UserApi.php @@ -5,6 +5,7 @@ use CrowdinApiClient\Model\ProjectMember; use CrowdinApiClient\Model\ProjectMemberAddedStatistics; use CrowdinApiClient\Model\User; +use CrowdinApiClient\Model\UserReportSettingsTemplate; use CrowdinApiClient\ModelCollection; /** @@ -138,4 +139,95 @@ public function deleteMemberFromProject(int $projectId, int $memberId): void { $this->_delete(sprintf('projects/%d/members/%s', $projectId, $memberId)); } + + /** + * List User Report Settings Templates + * @link https://developer.crowdin.com/api/v2/#operation/api.users.reports.settings-templates.getMany API Documentation + * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.users.reports.settings-templates.getMany API Documentation Enterprise + * + * @param int $userId + * @param array $params + * integer $params[limit]
+ * integer $params[offset] + * @return ModelCollection + */ + public function listReportSettingsTemplates(int $userId, array $params = []): ModelCollection + { + return $this->_list( + sprintf('users/%d/reports/settings-templates', $userId), + UserReportSettingsTemplate::class, + $params + ); + } + + /** + * Create User Report Settings Template + * @link https://developer.crowdin.com/api/v2/#operation/api.users.reports.settings-templates.post API Documentation + * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.users.reports.settings-templates.post API Documentation Enterprise + * + * @param int $userId + * @param array $data + * string $data[name] required
+ * string $data[currency] required
+ * string $data[unit] required
+ * array $data[config] required + * @return UserReportSettingsTemplate|null + */ + public function createReportSettingsTemplate(int $userId, array $data): ?UserReportSettingsTemplate + { + return $this->_create( + sprintf('users/%d/reports/settings-templates', $userId), + UserReportSettingsTemplate::class, + $data + ); + } + + /** + * Get User Report Settings Template + * @link https://developer.crowdin.com/api/v2/#operation/api.users.reports.settings-templates.get API Documentation + * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.users.reports.settings-templates.get API Documentation Enterprise + * + * @param int $userId + * @param int $reportSettingsTemplateId + * @return UserReportSettingsTemplate|null + */ + public function getReportSettingsTemplate(int $userId, int $reportSettingsTemplateId): ?UserReportSettingsTemplate + { + return $this->_get( + sprintf('users/%d/reports/settings-templates/%d', $userId, $reportSettingsTemplateId), + UserReportSettingsTemplate::class + ); + } + + /** + * Delete User Report Settings Template + * @link https://developer.crowdin.com/api/v2/#operation/api.users.reports.settings-templates.delete API Documentation + * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.users.reports.settings-templates.delete API Documentation Enterprise + * + * @param int $userId + * @param int $reportSettingsTemplateId + */ + public function deleteReportSettingsTemplate(int $userId, int $reportSettingsTemplateId): void + { + $this->_delete(sprintf('users/%d/reports/settings-templates/%d', $userId, $reportSettingsTemplateId)); + } + + /** + * Update User Report Settings Template + * @link https://developer.crowdin.com/api/v2/#operation/api.users.reports.settings-templates.patch API Documentation + * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.users.reports.settings-templates.patch API Documentation Enterprise + * + * @param int $userId + * @param UserReportSettingsTemplate $reportSettingsTemplate + * @return UserReportSettingsTemplate|null + */ + public function updateReportSettingsTemplate( + int $userId, + UserReportSettingsTemplate $reportSettingsTemplate + ): ?UserReportSettingsTemplate { + return $this->_update( + sprintf('users/%d/reports/settings-templates/%d', $userId, $reportSettingsTemplate->getId()), + $reportSettingsTemplate + ); + } } diff --git a/src/CrowdinApiClient/Model/HourlyBaseRates.php b/src/CrowdinApiClient/Model/HourlyBaseRates.php new file mode 100644 index 00000000..d37cf539 --- /dev/null +++ b/src/CrowdinApiClient/Model/HourlyBaseRates.php @@ -0,0 +1,40 @@ +hourly = (float)$this->getDataProperty('hourly'); + } + + public function getHourly(): float + { + return $this->hourly; + } + + public function setHourly(float $hourly): void + { + $this->hourly = $hourly; + } + + public function toArray(): array + { + return [ + 'hourly' => $this->hourly, + ]; + } +} diff --git a/src/CrowdinApiClient/Model/HourlyIndividualRates.php b/src/CrowdinApiClient/Model/HourlyIndividualRates.php new file mode 100644 index 00000000..71e13a31 --- /dev/null +++ b/src/CrowdinApiClient/Model/HourlyIndividualRates.php @@ -0,0 +1,112 @@ +languageIds = array_map(static function ($languageId): string { + return (string)$languageId; + }, $this->getDataProperty('languageIds') ?? []); + $this->userIds = array_map(static function ($userId): int { + return (int)$userId; + }, $this->getDataProperty('userIds') ?? []); + $this->hourly = (float)$this->getDataProperty('hourly'); + } + + /** + * @return string[] + */ + public function getLanguageIds(): array + { + return $this->languageIds; + } + + /** + * @param string[] $languageIds + */ + public function setLanguageIds(array $languageIds): void + { + if ($languageIds === []) { + throw new InvalidArgumentException('Argument "languageIds" cannot be empty'); + } + + foreach ($languageIds as $languageId) { + if (!is_string($languageId)) { + throw new InvalidArgumentException('Argument "languageIds" must be an array of strings'); + } + } + + $this->languageIds = $languageIds; + } + + /** + * @return int[] + */ + public function getUserIds(): array + { + return $this->userIds; + } + + /** + * @param int[] $userIds + */ + public function setUserIds(array $userIds): void + { + if ($userIds === []) { + throw new InvalidArgumentException('Argument "userIds" cannot be empty'); + } + + foreach ($userIds as $userId) { + if (!is_int($userId)) { + throw new InvalidArgumentException('Argument "userIds" must be an array of integers'); + } + } + + $this->userIds = $userIds; + } + + public function getHourly(): float + { + return $this->hourly; + } + + public function setHourly(float $hourly): void + { + $this->hourly = $hourly; + } + + public function toArray(): array + { + return [ + 'languageIds' => $this->languageIds, + 'userIds' => $this->userIds, + 'hourly' => $this->hourly, + ]; + } +} diff --git a/src/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfig.php b/src/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfig.php new file mode 100644 index 00000000..e2aa4ba1 --- /dev/null +++ b/src/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfig.php @@ -0,0 +1,81 @@ +baseRates = new HourlyBaseRates($this->getDataProperty('baseRates') ?? []); + $this->individualRates = array_map(static function (array $individualRates): HourlyIndividualRates { + return new HourlyIndividualRates($individualRates); + }, $this->getDataProperty('individualRates') ?? []); + } + + public function getBaseRates(): HourlyBaseRates + { + return $this->baseRates; + } + + public function setBaseRates(HourlyBaseRates $baseRates): void + { + $this->baseRates = $baseRates; + } + + /** + * @return HourlyIndividualRates[] + */ + public function getIndividualRates(): array + { + return $this->individualRates; + } + + /** + * @param HourlyIndividualRates[] $individualRates + */ + public function setIndividualRates(array $individualRates): void + { + if ($individualRates === []) { + throw new InvalidArgumentException('Argument "individualRates" cannot be empty'); + } + + foreach ($individualRates as $individualRate) { + if (!$individualRate instanceof HourlyIndividualRates) { + throw new InvalidArgumentException( + 'Argument "individualRates" must contain only IndividualRates objects' + ); + } + } + + $this->individualRates = $individualRates; + } + + public function toArray(): array + { + return [ + 'baseRates' => $this->baseRates->toArray(), + 'individualRates' => array_map(static function (HourlyIndividualRates $individualRate): array { + return $individualRate->toArray(); + }, $this->individualRates), + ]; + } +} diff --git a/src/CrowdinApiClient/Model/IndividualRates.php b/src/CrowdinApiClient/Model/IndividualRates.php index e14ae577..5a652fd1 100644 --- a/src/CrowdinApiClient/Model/IndividualRates.php +++ b/src/CrowdinApiClient/Model/IndividualRates.php @@ -54,7 +54,7 @@ public function getLanguageIds(): array } /** - * @param array $languageIds + * @param string[] $languageIds */ public function setLanguageIds(array $languageIds): void { diff --git a/src/CrowdinApiClient/Model/Report.php b/src/CrowdinApiClient/Model/Report.php index 60ffe655..ba67962a 100644 --- a/src/CrowdinApiClient/Model/Report.php +++ b/src/CrowdinApiClient/Model/Report.php @@ -61,12 +61,14 @@ class Report extends BaseModel public const UNIT_WORDS = 'words'; public const UNIT_CHARS = 'chars'; public const UNIT_CHARS_WITH_SPACES = 'chars_with_spaces'; + public const UNIT_HOURS = 'hours'; public const UNITS = [ self::UNIT_STRINGS, self::UNIT_WORDS, self::UNIT_CHARS, self::UNIT_CHARS_WITH_SPACES, + self::UNIT_HOURS, ]; /** diff --git a/src/CrowdinApiClient/Model/ReportSettingsTemplateConfig.php b/src/CrowdinApiClient/Model/ReportSettingsTemplateConfig.php index 6e93df51..1b4580ba 100644 --- a/src/CrowdinApiClient/Model/ReportSettingsTemplateConfig.php +++ b/src/CrowdinApiClient/Model/ReportSettingsTemplateConfig.php @@ -26,6 +26,26 @@ class ReportSettingsTemplateConfig extends BaseModel */ protected $netRateSchemes; + /** + * @var bool + */ + protected $calculateInternalMatches; + + /** + * @var bool + */ + protected $includePreTranslatedStrings; + + /** + * @var bool + */ + protected $excludeApprovalsForEditedTranslations; + + /** + * @var bool + */ + protected $preTranslatedStringsCategorizationAdjustment; + public function __construct(array $data = []) { parent::__construct($data); @@ -35,6 +55,14 @@ public function __construct(array $data = []) return new IndividualRates($individualRates); }, $this->getDataProperty('individualRates') ?? []); $this->netRateSchemes = new NetRateSchemes($this->getDataProperty('netRateSchemes') ?? []); + $this->calculateInternalMatches = (bool)$this->getDataProperty('calculateInternalMatches'); + $this->includePreTranslatedStrings = (bool)$this->getDataProperty('includePreTranslatedStrings'); + $this->excludeApprovalsForEditedTranslations = (bool)$this->getDataProperty( + 'excludeApprovalsForEditedTranslations' + ); + $this->preTranslatedStringsCategorizationAdjustment = (bool)$this->getDataProperty( + 'preTranslatedStringsCategorizationAdjustment' + ); } public function getBaseRates(): BaseRates @@ -85,6 +113,47 @@ public function setNetRateSchemes(NetRateSchemes $netRateSchemes): void $this->netRateSchemes = $netRateSchemes; } + public function getCalculateInternalMatches(): bool + { + return $this->calculateInternalMatches; + } + + public function setCalculateInternalMatches(bool $calculateInternalMatches): void + { + $this->calculateInternalMatches = $calculateInternalMatches; + } + + public function getIncludePreTranslatedStrings(): bool + { + return $this->includePreTranslatedStrings; + } + + public function setIncludePreTranslatedStrings(bool $includePreTranslatedStrings): void + { + $this->includePreTranslatedStrings = $includePreTranslatedStrings; + } + + public function getExcludeApprovalsForEditedTranslations(): bool + { + return $this->excludeApprovalsForEditedTranslations; + } + + public function setExcludeApprovalsForEditedTranslations(bool $excludeApprovalsForEditedTranslations): void + { + $this->excludeApprovalsForEditedTranslations = $excludeApprovalsForEditedTranslations; + } + + public function getPreTranslatedStringsCategorizationAdjustment(): bool + { + return $this->preTranslatedStringsCategorizationAdjustment; + } + + public function setPreTranslatedStringsCategorizationAdjustment( + bool $preTranslatedStringsCategorizationAdjustment + ): void { + $this->preTranslatedStringsCategorizationAdjustment = $preTranslatedStringsCategorizationAdjustment; + } + public function toArray(): array { return [ @@ -93,6 +162,10 @@ public function toArray(): array return $individualRate->toArray(); }, $this->individualRates), 'netRateSchemes' => $this->netRateSchemes->toArray(), + 'calculateInternalMatches' => $this->calculateInternalMatches, + 'includePreTranslatedStrings' => $this->includePreTranslatedStrings, + 'excludeApprovalsForEditedTranslations' => $this->excludeApprovalsForEditedTranslations, + 'preTranslatedStringsCategorizationAdjustment' => $this->preTranslatedStringsCategorizationAdjustment, ]; } } diff --git a/src/CrowdinApiClient/Model/UserReportSettingsTemplate.php b/src/CrowdinApiClient/Model/UserReportSettingsTemplate.php new file mode 100644 index 00000000..ae262d15 --- /dev/null +++ b/src/CrowdinApiClient/Model/UserReportSettingsTemplate.php @@ -0,0 +1,158 @@ +id = (int)$this->getDataProperty('id'); + $this->name = (string)$this->getDataProperty('name'); + $this->currency = (string)$this->getDataProperty('currency'); + $this->unit = (string)$this->getDataProperty('unit'); + $this->createdAt = (string)$this->getDataProperty('createdAt'); + $this->updatedAt = $this->getDataProperty('updatedAt') ? (string)$this->getDataProperty('updatedAt') : null; + + if ($this->unit === Report::UNIT_HOURS) { + $this->config = new HourlyReportSettingsTemplateConfig($this->getDataProperty('config') ?? []); + } else { + $this->config = new ReportSettingsTemplateConfig($this->getDataProperty('config') ?? []); + } + } + + public function getId(): int + { + return $this->id; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): void + { + $this->name = $name; + } + + public function getCurrency(): string + { + return $this->currency; + } + + public function setCurrency(string $currency): void + { + if (!in_array($currency, Report::CURRENCIES, true)) { + throw new InvalidArgumentException( + sprintf( + 'Argument "currency" must be one of the following values: %s', + implode(', ', Report::CURRENCIES) + ) + ); + } + + $this->currency = $currency; + } + + public function getUnit(): string + { + return $this->unit; + } + + public function setUnit(string $unit): void + { + if (!in_array($unit, Report::UNITS, true)) { + throw new InvalidArgumentException( + sprintf( + 'Argument "unit" must be one of the following values: %s', + implode(', ', Report::UNITS) + ) + ); + } + + $this->unit = $unit; + } + + /** + * @return HourlyReportSettingsTemplateConfig|ReportSettingsTemplateConfig + */ + public function getConfig() + { + return $this->config; + } + + /** + * @param HourlyReportSettingsTemplateConfig|ReportSettingsTemplateConfig $config + */ + public function setConfig($config): void + { + $this->config = $config; + } + + public function getCreatedAt(): string + { + return $this->createdAt; + } + + public function getUpdatedAt(): ?string + { + return $this->updatedAt; + } + + public function toArray(): array + { + return [ + 'id' => $this->id, + 'name' => $this->name, + 'currency' => $this->currency, + 'unit' => $this->unit, + 'config' => $this->config->toArray(), + 'createdAt' => $this->createdAt, + 'updatedAt' => $this->updatedAt, + ]; + } +} diff --git a/tests/CrowdinApiClient/Api/UserApiTest.php b/tests/CrowdinApiClient/Api/UserApiTest.php index 263b547b..ef2be90d 100644 --- a/tests/CrowdinApiClient/Api/UserApiTest.php +++ b/tests/CrowdinApiClient/Api/UserApiTest.php @@ -4,7 +4,10 @@ use CrowdinApiClient\Model\ProjectMember; use CrowdinApiClient\Model\ProjectMemberAddedStatistics; +use CrowdinApiClient\Model\ReportSettingsTemplateConfig; use CrowdinApiClient\Model\User; +use CrowdinApiClient\Model\UserReportSettingsTemplate; +use CrowdinApiClient\ModelCollection; class UserApiTest extends AbstractTestApi { @@ -264,7 +267,7 @@ public function testReplaceProjectMemberPermissions(): void 'name' => 'translator', 'permissions' => [ 'allLanguages' => true, - 'languageAccess' => [] + 'languageAccess' => [], ], ]; @@ -285,7 +288,7 @@ public function testReplaceProjectMemberPermissions(): void 'name' => 'translator', 'permissions' => [ 'allLanguages' => true, - 'languageAccess' => [] + 'languageAccess' => [], ], ], 'avatarUrl' => '', @@ -310,4 +313,359 @@ public function testDeleteMemberFromProject(): void $this->crowdin->user->deleteMemberFromProject(1, 1); } + + public function testListReportsSettingsTemplates(): void + { + $this->mockRequestGet( + '/users/1/reports/settings-templates', + json_encode([ + 'data' => [ + [ + 'data' => [ + 'id' => 1, + 'name' => 'Default template', + 'currency' => 'USD', + 'unit' => 'words', + 'config' => [ + 'baseRates' => [ + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + 'individualRates' => [ + [ + 'languageIds' => ['uk'], + 'userIds' => [], + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + ], + 'netRateSchemes' => [ + 'tmMatch' => [ + [ + 'matchType' => '100', + 'price' => 0.1, + ], + ], + 'mtMatch' => [ + [ + 'matchType' => '100-82', + 'price' => 0.1, + ], + ], + 'aiMatch' => [ + [ + 'matchType' => '100-74', + 'price' => 0.1, + ], + ], + 'suggestionMatch' => [ + [ + 'matchType' => 'perfect', + 'price' => 0.1, + ], + ], + ], + 'calculateInternalMatches' => false, + 'includePreTranslatedStrings' => false, + 'excludeApprovalsForEditedTranslations' => false, + 'preTranslatedStringsCategorizationAdjustment' => false, + ], + 'createdAt' => '2019-09-23T11:26:54+00:00', + 'updatedAt' => '2019-09-23T11:26:54+00:00', + ], + ], + ], + 'pagination' => [ + 'offset' => 0, + 'limit' => 25, + ], + ]) + ); + + $templates = $this->crowdin->user->listReportSettingsTemplates(1); + + $this->assertInstanceOf(ModelCollection::class, $templates); + $this->assertCount(1, $templates); + $this->assertInstanceOf(UserReportSettingsTemplate::class, $templates[0]); + $this->assertEquals(1, $templates[0]->getId()); + $this->assertEquals('Default template', $templates[0]->getName()); + $this->assertEquals('USD', $templates[0]->getCurrency()); + $this->assertEquals('words', $templates[0]->getUnit()); + $this->assertInstanceOf(ReportSettingsTemplateConfig::class, $templates[0]->getConfig()); + } + + public function testCreateReportSettingsTemplate(): void + { + $this->mockRequestPost( + '/users/1/reports/settings-templates', + json_encode([ + 'name' => 'Default template', + 'currency' => 'USD', + 'unit' => 'words', + 'config' => [ + 'baseRates' => [ + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + 'individualRates' => [], + 'netRateSchemes' => [ + 'tmMatch' => [], + 'mtMatch' => [], + 'aiMatch' => [], + 'suggestionMatch' => [], + ], + ], + ]), + json_encode([ + 'data' => [ + 'id' => 1, + 'name' => 'Default template', + 'currency' => 'USD', + 'unit' => 'words', + 'config' => [ + 'baseRates' => [ + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + 'individualRates' => [], + 'netRateSchemes' => [ + 'tmMatch' => [], + 'mtMatch' => [], + 'aiMatch' => [], + 'suggestionMatch' => [], + ], + ], + 'isPublic' => false, + 'isGlobal' => false, + 'createdAt' => '2019-09-23T11:26:54+00:00', + 'updatedAt' => null, + ], + ]) + ); + + $params = [ + 'name' => 'Default template', + 'currency' => 'USD', + 'unit' => 'words', + 'config' => [ + 'baseRates' => [ + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + 'individualRates' => [], + 'netRateSchemes' => [ + 'tmMatch' => [], + 'mtMatch' => [], + 'aiMatch' => [], + 'suggestionMatch' => [], + ], + ], + ]; + + $template = $this->crowdin->user->createReportSettingsTemplate(1, $params); + + $this->assertInstanceOf(UserReportSettingsTemplate::class, $template); + $this->assertEquals(1, $template->getId()); + $this->assertEquals('Default template', $template->getName()); + $this->assertEquals('USD', $template->getCurrency()); + } + + public function testGetReportSettingsTemplate(): void + { + $this->mockRequestGet( + '/users/1/reports/settings-templates/1', + json_encode([ + 'data' => [ + 'id' => 1, + 'name' => 'Default template', + 'currency' => 'USD', + 'unit' => 'words', + 'config' => [ + 'baseRates' => [ + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + 'individualRates' => [ + [ + 'languageIds' => ['uk'], + 'userIds' => [], + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + ], + 'netRateSchemes' => [ + 'tmMatch' => [ + [ + 'matchType' => '100', + 'price' => 0.1, + ], + ], + 'mtMatch' => [ + [ + 'matchType' => '100-82', + 'price' => 0.1, + ], + ], + 'aiMatch' => [ + [ + 'matchType' => '100-74', + 'price' => 0.1, + ], + ], + 'suggestionMatch' => [ + [ + 'matchType' => 'perfect', + 'price' => 0.1, + ], + ], + ], + 'calculateInternalMatches' => false, + 'includePreTranslatedStrings' => false, + 'excludeApprovalsForEditedTranslations' => false, + 'preTranslatedStringsCategorizationAdjustment' => false, + ], + 'createdAt' => '2019-09-23T11:26:54+00:00', + 'updatedAt' => '2019-09-23T11:26:54+00:00', + ], + ]) + ); + + $template = $this->crowdin->user->getReportSettingsTemplate(1, 1); + + $this->assertInstanceOf(UserReportSettingsTemplate::class, $template); + $this->assertEquals(1, $template->getId()); + $this->assertEquals('Default template', $template->getName()); + $this->assertEquals('USD', $template->getCurrency()); + $this->assertInstanceOf(ReportSettingsTemplateConfig::class, $template->getConfig()); + } + + public function testDeleteReportSettingsTemplate(): void + { + $this->mockRequestDelete('/users/1/reports/settings-templates/1'); + + $this->crowdin->user->deleteReportSettingsTemplate(1, 1); + } + + public function testUpdateReportSettingsTemplate(): void + { + $this->mockRequestPatch( + '/users/1/reports/settings-templates/1', + json_encode([ + 'data' => [ + 'id' => 1, + 'name' => 'Updated template name', + 'currency' => 'EUR', + 'unit' => 'words', + 'config' => [ + 'baseRates' => [ + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + 'individualRates' => [ + [ + 'languageIds' => ['uk'], + 'userIds' => [], + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + ], + 'netRateSchemes' => [ + 'tmMatch' => [ + [ + 'matchType' => '100', + 'price' => 0.1, + ], + ], + 'mtMatch' => [ + [ + 'matchType' => '100-82', + 'price' => 0.1, + ], + ], + 'aiMatch' => [ + [ + 'matchType' => '100-74', + 'price' => 0.1, + ], + ], + 'suggestionMatch' => [ + [ + 'matchType' => 'perfect', + 'price' => 0.1, + ], + ], + ], + 'calculateInternalMatches' => false, + 'includePreTranslatedStrings' => false, + 'excludeApprovalsForEditedTranslations' => false, + 'preTranslatedStringsCategorizationAdjustment' => false, + ], + 'createdAt' => '2019-09-23T11:26:54+00:00', + 'updatedAt' => '2019-09-23T11:26:54+00:00', + ], + ]) + ); + + $template = new UserReportSettingsTemplate([ + 'id' => 1, + 'name' => 'Default template', + 'currency' => 'USD', + 'unit' => 'words', + 'config' => [ + 'baseRates' => [ + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + 'individualRates' => [ + [ + 'languageIds' => ['uk'], + 'userIds' => [], + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + ], + 'netRateSchemes' => [ + 'tmMatch' => [ + [ + 'matchType' => '100', + 'price' => 0.1, + ], + ], + 'mtMatch' => [ + [ + 'matchType' => '100-82', + 'price' => 0.1, + ], + ], + 'aiMatch' => [ + [ + 'matchType' => '100-74', + 'price' => 0.1, + ], + ], + 'suggestionMatch' => [ + [ + 'matchType' => 'perfect', + 'price' => 0.1, + ], + ], + ], + 'calculateInternalMatches' => false, + 'includePreTranslatedStrings' => false, + 'excludeApprovalsForEditedTranslations' => false, + 'preTranslatedStringsCategorizationAdjustment' => false, + ], + 'createdAt' => '2019-09-23T11:26:54+00:00', + 'updatedAt' => '2019-09-23T11:26:54+00:00', + ]); + $template->setName('Updated template name'); + $template->setCurrency('EUR'); + + $result = $this->crowdin->user->updateReportSettingsTemplate(1, $template); + + $this->assertInstanceOf(UserReportSettingsTemplate::class, $result); + $this->assertEquals(1, $result->getId()); + $this->assertEquals('Updated template name', $result->getName()); + $this->assertEquals('EUR', $result->getCurrency()); + } } diff --git a/tests/CrowdinApiClient/Model/HourlyBaseRatesTest.php b/tests/CrowdinApiClient/Model/HourlyBaseRatesTest.php new file mode 100644 index 00000000..d54e6302 --- /dev/null +++ b/tests/CrowdinApiClient/Model/HourlyBaseRatesTest.php @@ -0,0 +1,35 @@ + 0.1, + ]; + + public function testLoadData(): void + { + $hourlyBaseRates = new HourlyBaseRates($this->data); + $this->assertEquals($this->data['hourly'], $hourlyBaseRates->getHourly()); + } + + public function testSetData(): void + { + $hourlyBaseRates = new HourlyBaseRates($this->data); + $hourlyBaseRates->setHourly(0.2); + + $this->assertEquals(0.2, $hourlyBaseRates->getHourly()); + } + + public function testToArray(): void + { + $hourlyBaseRates = new HourlyBaseRates($this->data); + $this->assertEquals($this->data, $hourlyBaseRates->toArray()); + } +} diff --git a/tests/CrowdinApiClient/Model/HourlyIndividualRatesTest.php b/tests/CrowdinApiClient/Model/HourlyIndividualRatesTest.php new file mode 100644 index 00000000..2f4e664d --- /dev/null +++ b/tests/CrowdinApiClient/Model/HourlyIndividualRatesTest.php @@ -0,0 +1,107 @@ + ['en', 'uk', 'de'], + 'userIds' => [1, 2, 3], + 'hourly' => 0.1, + ]; + + public function testLoadData(): void + { + $individualRates = new HourlyIndividualRates($this->data); + $this->assertEquals($this->data['languageIds'], $individualRates->getLanguageIds()); + $this->assertEquals($this->data['userIds'], $individualRates->getUserIds()); + $this->assertEquals($this->data['hourly'], $individualRates->getHourly()); + } + + public function testSetData(): void + { + $languageIds = ['en', 'uk', 'de', 'fr']; + $userIds = [8]; + $hourly = 0.2; + + $individualRates = new HourlyIndividualRates($this->data); + $individualRates->setLanguageIds($languageIds); + $individualRates->setUserIds($userIds); + $individualRates->setHourly($hourly); + + $this->assertEquals($languageIds, $individualRates->getLanguageIds()); + $this->assertEquals($userIds, $individualRates->getUserIds()); + $this->assertEquals($hourly, $individualRates->getHourly()); + } + + public function testToArray(): void + { + $individualRates = new HourlyIndividualRates($this->data); + $result = $individualRates->toArray(); + + $this->assertArrayHasKey('languageIds', $result); + $this->assertArrayHasKey('userIds', $result); + $this->assertArrayHasKey('hourly', $result); + $this->assertEquals($this->data['languageIds'], $result['languageIds']); + $this->assertEquals($this->data['userIds'], $result['userIds']); + $this->assertEquals($this->data['hourly'], $result['hourly']); + } + + public function languageIdsExceptionDataProvider(): array + { + return [ + 'empty' => [ + 'languageIds' => [], + 'exceptionMessage' => 'Argument "languageIds" cannot be empty', + ], + 'invalidType' => [ + 'languageIds' => [1, 2, 3], + 'exceptionMessage' => 'Argument "languageIds" must be an array of strings', + ], + ]; + } + + /** + * @dataProvider languageIdsExceptionDataProvider + */ + public function testSetLanguageIdsEmptyThrowsException(array $languageIds, string $exceptionMessage): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage($exceptionMessage); + + $individualRates = new HourlyIndividualRates(); + $individualRates->setLanguageIds($languageIds); + } + + public function userIdsExceptionDataProvider(): array + { + return [ + 'empty' => [ + 'userIds' => [], + 'exceptionMessage' => 'Argument "userIds" cannot be empty', + ], + 'invalidType' => [ + 'userIds' => ['123'], + 'exceptionMessage' => 'Argument "userIds" must be an array of integers', + ] + ]; + } + + /** + * @dataProvider userIdsExceptionDataProvider + */ + public function testSetUserIdsException(array $userIds, string $exceptionMessage): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage($exceptionMessage); + + $individualRates = new HourlyIndividualRates(); + $individualRates->setUserIds($userIds); + } +} diff --git a/tests/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfigTest.php b/tests/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfigTest.php new file mode 100644 index 00000000..ce91ecb9 --- /dev/null +++ b/tests/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfigTest.php @@ -0,0 +1,106 @@ + [ + 'hourly' => 0.1, + ], + 'individualRates' => [ + [ + 'languageIds' => ['uk'], + 'userIds' => [8], + 'hourly' => 0.1, + ], + ], + ]; + + public function testLoadData(): void + { + $reportSettingsTemplateConfig = new HourlyReportSettingsTemplateConfig($this->data); + + $this->assertEquals( + $this->data['baseRates'], + $reportSettingsTemplateConfig->getBaseRates()->toArray() + ); + $this->assertEquals( + $this->data['individualRates'], + array_map(static function (HourlyIndividualRates $individualRates): array { + return $individualRates->toArray(); + }, $reportSettingsTemplateConfig->getIndividualRates()) + ); + } + + public function testSetData(): void + { + $baseRates = new HourlyBaseRates(['hourly' => 0.2]); + $individualRates = [ + new HourlyIndividualRates([ + [ + 'languageIds' => ['uk', 'en', 'jp'], + 'userIds' => [8], + 'hourly' => 0.3, + ], + ]), + ]; + + $reportSettingsTemplateConfig = new HourlyReportSettingsTemplateConfig($this->data); + $reportSettingsTemplateConfig->setBaseRates($baseRates); + $reportSettingsTemplateConfig->setIndividualRates($individualRates); + + $this->assertEquals( + $baseRates->toArray(), + $reportSettingsTemplateConfig->getBaseRates()->toArray() + ); + $this->assertEquals( + array_map(static function (HourlyIndividualRates $individualRates): array { + return $individualRates->toArray(); + }, $individualRates), + array_map(static function (HourlyIndividualRates $individualRates): array { + return $individualRates->toArray(); + }, $reportSettingsTemplateConfig->getIndividualRates()) + ); + } + + public function individualRatesExceptionDataProvider(): array + { + return [ + 'empty' => [ + 'individualRates' => [], + 'exceptionMessage' => 'Argument "individualRates" cannot be empty', + ], + 'invalidType' => [ + 'individualRates' => [ + [], + ], + 'exceptionMessage' => 'Argument "individualRates" must contain only IndividualRates objects', + ], + ]; + } + + /** + * @dataProvider individualRatesExceptionDataProvider + */ + public function testSetIndividualRatesException(array $individualRates, string $exceptionMessage): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage($exceptionMessage); + + (new HourlyReportSettingsTemplateConfig($this->data))->setIndividualRates($individualRates); + } + + public function testToArray(): void + { + $this->assertSame($this->data, (new HourlyReportSettingsTemplateConfig($this->data))->toArray()); + } +} diff --git a/tests/CrowdinApiClient/Model/ReportSettingsTemplateConfigTest.php b/tests/CrowdinApiClient/Model/ReportSettingsTemplateConfigTest.php index 2e682caa..b3c7d6ba 100644 --- a/tests/CrowdinApiClient/Model/ReportSettingsTemplateConfigTest.php +++ b/tests/CrowdinApiClient/Model/ReportSettingsTemplateConfigTest.php @@ -56,17 +56,45 @@ class ReportSettingsTemplateConfigTest extends TestCase ], ], ], + 'calculateInternalMatches' => true, + 'includePreTranslatedStrings' => false, + 'excludeApprovalsForEditedTranslations' => true, + 'preTranslatedStringsCategorizationAdjustment' => false, ]; - /** - * @var ReportSettingsTemplateConfig - */ - public $reportSettingsTemplateConfig; - public function testLoadData(): void { - $this->reportSettingsTemplateConfig = new ReportSettingsTemplateConfig($this->data); - $this->checkData(); + $reportSettingsTemplateConfig = new ReportSettingsTemplateConfig($this->data); + $this->assertEquals( + $this->data['baseRates'], + $reportSettingsTemplateConfig->getBaseRates()->toArray() + ); + $this->assertEquals( + $this->data['individualRates'], + array_map(static function (IndividualRates $individualRates): array { + return $individualRates->toArray(); + }, $reportSettingsTemplateConfig->getIndividualRates()) + ); + $this->assertEquals( + $this->data['netRateSchemes'], + $reportSettingsTemplateConfig->getNetRateSchemes()->toArray() + ); + $this->assertEquals( + $this->data['calculateInternalMatches'], + $reportSettingsTemplateConfig->getCalculateInternalMatches() + ); + $this->assertEquals( + $this->data['includePreTranslatedStrings'], + $reportSettingsTemplateConfig->getIncludePreTranslatedStrings() + ); + $this->assertEquals( + $this->data['excludeApprovalsForEditedTranslations'], + $reportSettingsTemplateConfig->getExcludeApprovalsForEditedTranslations() + ); + $this->assertEquals( + $this->data['preTranslatedStringsCategorizationAdjustment'], + $reportSettingsTemplateConfig->getPreTranslatedStringsCategorizationAdjustment() + ); } /** @@ -74,46 +102,52 @@ public function testLoadData(): void */ public function testSetData(): void { - $this->reportSettingsTemplateConfig = new ReportSettingsTemplateConfig(); - $this->reportSettingsTemplateConfig->setBaseRates(new BaseRates($this->data['baseRates'])); - $this->reportSettingsTemplateConfig->setIndividualRates( + $reportSettingsTemplateConfig = new ReportSettingsTemplateConfig(); + $reportSettingsTemplateConfig->setBaseRates(new BaseRates($this->data['baseRates'])); + $reportSettingsTemplateConfig->setIndividualRates( array_map(static function (array $individualRates): IndividualRates { return new IndividualRates($individualRates); }, $this->data['individualRates']) ); - $this->reportSettingsTemplateConfig->setNetRateSchemes(new NetRateSchemes($this->data['netRateSchemes'])); + $reportSettingsTemplateConfig->setNetRateSchemes(new NetRateSchemes($this->data['netRateSchemes'])); + $reportSettingsTemplateConfig->setCalculateInternalMatches($this->data['calculateInternalMatches']); + $reportSettingsTemplateConfig->setIncludePreTranslatedStrings($this->data['includePreTranslatedStrings']); + $reportSettingsTemplateConfig->setExcludeApprovalsForEditedTranslations( + $this->data['excludeApprovalsForEditedTranslations'] + ); + $reportSettingsTemplateConfig->setPreTranslatedStringsCategorizationAdjustment( + $this->data['preTranslatedStringsCategorizationAdjustment'] + ); $this->assertEquals( $this->data['baseRates'], - $this->reportSettingsTemplateConfig->getBaseRates()->toArray() + $reportSettingsTemplateConfig->getBaseRates()->toArray() ); $this->assertEquals( $this->data['individualRates'], array_map(static function (IndividualRates $individualRates): array { return $individualRates->toArray(); - }, $this->reportSettingsTemplateConfig->getIndividualRates()) + }, $reportSettingsTemplateConfig->getIndividualRates()) ); $this->assertEquals( $this->data['netRateSchemes'], - $this->reportSettingsTemplateConfig->getNetRateSchemes()->toArray() + $reportSettingsTemplateConfig->getNetRateSchemes()->toArray() ); - } - - public function checkData(): void - { $this->assertEquals( - $this->data['baseRates'], - $this->reportSettingsTemplateConfig->getBaseRates()->toArray() + $this->data['calculateInternalMatches'], + $reportSettingsTemplateConfig->getCalculateInternalMatches() ); $this->assertEquals( - $this->data['individualRates'], - array_map(static function (IndividualRates $individualRates): array { - return $individualRates->toArray(); - }, $this->reportSettingsTemplateConfig->getIndividualRates()) + $this->data['includePreTranslatedStrings'], + $reportSettingsTemplateConfig->getIncludePreTranslatedStrings() ); $this->assertEquals( - $this->data['netRateSchemes'], - $this->reportSettingsTemplateConfig->getNetRateSchemes()->toArray() + $this->data['excludeApprovalsForEditedTranslations'], + $reportSettingsTemplateConfig->getExcludeApprovalsForEditedTranslations() + ); + $this->assertEquals( + $this->data['preTranslatedStringsCategorizationAdjustment'], + $reportSettingsTemplateConfig->getPreTranslatedStringsCategorizationAdjustment() ); } diff --git a/tests/CrowdinApiClient/Model/ReportSettingsTemplateTest.php b/tests/CrowdinApiClient/Model/ReportSettingsTemplateTest.php index 16bdff0d..c17f800d 100644 --- a/tests/CrowdinApiClient/Model/ReportSettingsTemplateTest.php +++ b/tests/CrowdinApiClient/Model/ReportSettingsTemplateTest.php @@ -59,6 +59,10 @@ class ReportSettingsTemplateTest extends TestCase ], ], ], + 'calculateInternalMatches' => true, + 'includePreTranslatedStrings' => true, + 'excludeApprovalsForEditedTranslations' => true, + 'preTranslatedStringsCategorizationAdjustment' => true, ], 'isPublic' => true, 'isGlobal' => true, @@ -74,7 +78,15 @@ class ReportSettingsTemplateTest extends TestCase public function testLoadData(): void { $this->reportSettingsTemplate = new ReportSettingsTemplate($this->data); - $this->checkData(); + $this->assertEquals($this->data['id'], $this->reportSettingsTemplate->getId()); + $this->assertEquals($this->data['name'], $this->reportSettingsTemplate->getName()); + $this->assertEquals($this->data['currency'], $this->reportSettingsTemplate->getCurrency()); + $this->assertEquals($this->data['unit'], $this->reportSettingsTemplate->getUnit()); + $this->assertEquals($this->data['config'], $this->reportSettingsTemplate->getConfig()->toArray()); + $this->assertEquals($this->data['isPublic'], $this->reportSettingsTemplate->getIsPublic()); + $this->assertEquals($this->data['isGlobal'], $this->reportSettingsTemplate->getIsGlobal()); + $this->assertEquals($this->data['createdAt'], $this->reportSettingsTemplate->getCreatedAt()); + $this->assertEquals($this->data['updatedAt'], $this->reportSettingsTemplate->getUpdatedAt()); } /** @@ -96,19 +108,6 @@ public function testSetData(): void $this->assertEquals($this->data['isPublic'], $this->reportSettingsTemplate->getIsPublic()); } - public function checkData(): void - { - $this->assertEquals($this->data['id'], $this->reportSettingsTemplate->getId()); - $this->assertEquals($this->data['name'], $this->reportSettingsTemplate->getName()); - $this->assertEquals($this->data['currency'], $this->reportSettingsTemplate->getCurrency()); - $this->assertEquals($this->data['unit'], $this->reportSettingsTemplate->getUnit()); - $this->assertEquals($this->data['config'], $this->reportSettingsTemplate->getConfig()->toArray()); - $this->assertEquals($this->data['isPublic'], $this->reportSettingsTemplate->getIsPublic()); - $this->assertEquals($this->data['isGlobal'], $this->reportSettingsTemplate->getIsGlobal()); - $this->assertEquals($this->data['createdAt'], $this->reportSettingsTemplate->getCreatedAt()); - $this->assertEquals($this->data['updatedAt'], $this->reportSettingsTemplate->getUpdatedAt()); - } - public function testSetCurrencyException(): void { $this->expectException(InvalidArgumentException::class); diff --git a/tests/CrowdinApiClient/Model/UserReportSettingsTemplateTest.php b/tests/CrowdinApiClient/Model/UserReportSettingsTemplateTest.php new file mode 100644 index 00000000..84d127e7 --- /dev/null +++ b/tests/CrowdinApiClient/Model/UserReportSettingsTemplateTest.php @@ -0,0 +1,160 @@ + 12, + 'name' => 'Default template', + 'currency' => 'UAH', + 'unit' => 'words', + 'config' => [ + 'baseRates' => [ + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + 'individualRates' => [ + [ + 'languageIds' => ['uk'], + 'userIds' => [8], + 'fullTranslation' => 0.1, + 'proofread' => 0.12, + ], + ], + 'netRateSchemes' => [ + 'tmMatch' => [ + [ + 'matchType' => 'perfect', + 'price' => 0.1, + ], + [ + 'matchType' => '100', + 'price' => 0.2, + ], + ], + 'mtMatch' => [ + [ + 'matchType' => '100', + 'price' => 0.1, + ], + ], + 'aiMatch' => [ + [ + 'matchType' => '100', + 'price' => 0.1, + ], + ], + 'suggestionMatch' => [ + [ + 'matchType' => '100', + 'price' => 0.1, + ], + ], + ], + 'calculateInternalMatches' => true, + 'includePreTranslatedStrings' => true, + 'excludeApprovalsForEditedTranslations' => true, + 'preTranslatedStringsCategorizationAdjustment' => true, + ], + 'createdAt' => '2025-01-23T15:23:11+00:00', + 'updatedAt' => '2025-01-23T15:35:49+00:00', + ]; + + public function userReportSettingsTemplateDataProvider(): array + { + return [ + 'userReportSettingsTemplateForPostEditing' => [ + 'data' => $this->data, + 'expectedConfigClass' => ReportSettingsTemplateConfig::class, + ], + 'userReportSettingsTemplateForHours' => [ + 'data' => [ + 'id' => 12, + 'name' => 'Default template', + 'currency' => 'UAH', + 'unit' => 'hours', + 'config' => [ + 'baseRates' => [ + 'hourly' => 0.1, + ], + 'individualRates' => [ + [ + 'languageIds' => ['uk'], + 'userIds' => [8], + 'hourly' => 0.1, + ], + ], + ], + 'createdAt' => '2025-01-23T15:23:11+00:00', + 'updatedAt' => '2025-01-23T15:35:49+00:00', + ], + 'expectedConfigClass' => HourlyReportSettingsTemplateConfig::class, + ], + ]; + } + + /** + * @dataProvider userReportSettingsTemplateDataProvider + */ + public function testLoadData(array $data, string $expectedConfigClass): void + { + $template = new UserReportSettingsTemplate($data); + + $this->assertEquals($data['id'], $template->getId()); + $this->assertEquals($data['name'], $template->getName()); + $this->assertEquals($data['currency'], $template->getCurrency()); + $this->assertEquals($data['unit'], $template->getUnit()); + $this->assertInstanceOf($expectedConfigClass, $template->getConfig()); + $this->assertEquals($data['config'], $template->getConfig()->toArray()); + $this->assertEquals($data['createdAt'], $template->getCreatedAt()); + $this->assertEquals($data['updatedAt'], $template->getUpdatedAt()); + } + + public function testSetData(): void + { + $template = new UserReportSettingsTemplate($this->data); + + $config = $template->getConfig(); + $config->setCalculateInternalMatches(false); + + $template->setName('New name'); + $template->setCurrency('GBP'); + $template->setUnit('strings'); + $template->setConfig($config); + + $this->assertEquals('New name', $template->getName()); + $this->assertEquals('GBP', $template->getCurrency()); + $this->assertEquals('strings', $template->getUnit()); + $this->assertFalse($template->getConfig()->getCalculateInternalMatches()); + } + + public function testSetInvalidCurrency(): void + { + $this->expectException(InvalidArgumentException::class); + + $template = new UserReportSettingsTemplate($this->data); + $template->setCurrency('INVALID'); + } + + public function testSetInvalidUnit(): void + { + $this->expectException(InvalidArgumentException::class); + + $template = new UserReportSettingsTemplate($this->data); + $template->setUnit('INVALID'); + } + + public function testToArray(): void + { + $this->assertEquals($this->data, (new UserReportSettingsTemplate($this->data))->toArray()); + } +} From 036fb92881d8a9c68d5618354b59e875574aa6ab Mon Sep 17 00:00:00 2001 From: Bohdan Bobko <172895427+bhdnb@users.noreply.github.com> Date: Wed, 25 Mar 2026 19:51:13 +0200 Subject: [PATCH 2/2] Introduced HourlyUserReportSettingsTemplate --- src/CrowdinApiClient/Api/UserApi.php | 71 +++-- .../AbstractUserReportSettingsTemplate.php | 128 ++++++++ .../HourlyReportSettingsTemplateConfig.php | 2 +- .../HourlyUserReportSettingsTemplate.php | 60 ++++ .../Model/UserReportSettingsTemplate.php | 132 +------- tests/CrowdinApiClient/Api/UserApiTest.php | 297 ++++++++++++------ .../Model/HourlyIndividualRatesTest.php | 2 +- ...HourlyReportSettingsTemplateConfigTest.php | 10 +- .../HourlyUserReportSettingsTemplateTest.php | 97 ++++++ .../Model/UserReportSettingsTemplateTest.php | 57 +--- 10 files changed, 553 insertions(+), 303 deletions(-) create mode 100644 src/CrowdinApiClient/Model/AbstractUserReportSettingsTemplate.php create mode 100644 src/CrowdinApiClient/Model/HourlyUserReportSettingsTemplate.php create mode 100644 tests/CrowdinApiClient/Model/HourlyUserReportSettingsTemplateTest.php diff --git a/src/CrowdinApiClient/Api/UserApi.php b/src/CrowdinApiClient/Api/UserApi.php index 507273ab..3f1da006 100644 --- a/src/CrowdinApiClient/Api/UserApi.php +++ b/src/CrowdinApiClient/Api/UserApi.php @@ -2,8 +2,10 @@ namespace CrowdinApiClient\Api; +use CrowdinApiClient\Model\HourlyUserReportSettingsTemplate; use CrowdinApiClient\Model\ProjectMember; use CrowdinApiClient\Model\ProjectMemberAddedStatistics; +use CrowdinApiClient\Model\Report; use CrowdinApiClient\Model\User; use CrowdinApiClient\Model\UserReportSettingsTemplate; use CrowdinApiClient\ModelCollection; @@ -153,11 +155,22 @@ public function deleteMemberFromProject(int $projectId, int $memberId): void */ public function listReportSettingsTemplates(int $userId, array $params = []): ModelCollection { - return $this->_list( - sprintf('users/%d/reports/settings-templates', $userId), - UserReportSettingsTemplate::class, - $params - ); + $options = []; + if ($params !== []) { + $options['params'] = $params; + } + + $path = sprintf('users/%d/reports/settings-templates', $userId); + $response = $this->client->apiRequest('get', $path, null, $options); + + $modelCollection = new ModelCollection(); + $modelCollection->setPagination($response['pagination']); + + foreach ($response['data'] as $item) { + $modelCollection->add($this->makeUserReportSettingsTemplate($item['data'])); + } + + return $modelCollection; } /** @@ -171,15 +184,15 @@ public function listReportSettingsTemplates(int $userId, array $params = []): Mo * string $data[currency] required
* string $data[unit] required
* array $data[config] required - * @return UserReportSettingsTemplate|null + * @return UserReportSettingsTemplate|HourlyUserReportSettingsTemplate|null */ - public function createReportSettingsTemplate(int $userId, array $data): ?UserReportSettingsTemplate + public function createReportSettingsTemplate(int $userId, array $data) { - return $this->_create( - sprintf('users/%d/reports/settings-templates', $userId), - UserReportSettingsTemplate::class, - $data - ); + $path = sprintf('users/%d/reports/settings-templates', $userId); + $options = ['body' => json_encode($data), 'headers' => $this->getHeaders()]; + $response = $this->client->apiRequest('post', $path, null, $options); + + return $this->makeUserReportSettingsTemplate($response['data']); } /** @@ -189,14 +202,14 @@ public function createReportSettingsTemplate(int $userId, array $data): ?UserRep * * @param int $userId * @param int $reportSettingsTemplateId - * @return UserReportSettingsTemplate|null + * @return UserReportSettingsTemplate|HourlyUserReportSettingsTemplate|null */ - public function getReportSettingsTemplate(int $userId, int $reportSettingsTemplateId): ?UserReportSettingsTemplate + public function getReportSettingsTemplate(int $userId, int $reportSettingsTemplateId) { - return $this->_get( - sprintf('users/%d/reports/settings-templates/%d', $userId, $reportSettingsTemplateId), - UserReportSettingsTemplate::class - ); + $path = sprintf('users/%d/reports/settings-templates/%d', $userId, $reportSettingsTemplateId); + $response = $this->client->apiRequest('get', $path); + + return $this->makeUserReportSettingsTemplate($response['data']); } /** @@ -218,16 +231,26 @@ public function deleteReportSettingsTemplate(int $userId, int $reportSettingsTem * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.users.reports.settings-templates.patch API Documentation Enterprise * * @param int $userId - * @param UserReportSettingsTemplate $reportSettingsTemplate - * @return UserReportSettingsTemplate|null + * @param UserReportSettingsTemplate|HourlyUserReportSettingsTemplate $reportSettingsTemplate + * @return UserReportSettingsTemplate|HourlyUserReportSettingsTemplate|null */ - public function updateReportSettingsTemplate( - int $userId, - UserReportSettingsTemplate $reportSettingsTemplate - ): ?UserReportSettingsTemplate { + public function updateReportSettingsTemplate(int $userId, $reportSettingsTemplate) + { return $this->_update( sprintf('users/%d/reports/settings-templates/%d', $userId, $reportSettingsTemplate->getId()), $reportSettingsTemplate ); } + + /** + * @return HourlyUserReportSettingsTemplate|UserReportSettingsTemplate + */ + private function makeUserReportSettingsTemplate(array $data) + { + if (($data['unit'] ?? '') === Report::UNIT_HOURS) { + return new HourlyUserReportSettingsTemplate($data); + } + + return new UserReportSettingsTemplate($data); + } } diff --git a/src/CrowdinApiClient/Model/AbstractUserReportSettingsTemplate.php b/src/CrowdinApiClient/Model/AbstractUserReportSettingsTemplate.php new file mode 100644 index 00000000..f6dc4918 --- /dev/null +++ b/src/CrowdinApiClient/Model/AbstractUserReportSettingsTemplate.php @@ -0,0 +1,128 @@ +id; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): void + { + $this->name = $name; + } + + public function getCurrency(): string + { + return $this->currency; + } + + public function setCurrency(string $currency): void + { + if (!in_array($currency, Report::CURRENCIES, true)) { + throw new InvalidArgumentException( + sprintf( + 'Argument "currency" must be one of the following values: %s', + implode(', ', Report::CURRENCIES) + ) + ); + } + + $this->currency = $currency; + } + + public function getUnit(): string + { + return $this->unit; + } + + public function setUnit(string $unit): void + { + if (!in_array($unit, static::SUPPORTED_UNITS, true)) { + throw new InvalidArgumentException( + sprintf( + 'Argument "unit" must be one of the following values: %s', + implode(', ', static::SUPPORTED_UNITS) + ) + ); + } + + $this->unit = $unit; + } + + public function getCreatedAt(): string + { + return $this->createdAt; + } + + public function getUpdatedAt(): ?string + { + return $this->updatedAt; + } + + public function toArray(): array + { + return [ + 'id' => $this->id, + 'name' => $this->name, + 'currency' => $this->currency, + 'unit' => $this->unit, + 'config' => $this->config->toArray(), + 'createdAt' => $this->createdAt, + 'updatedAt' => $this->updatedAt, + ]; + } + + abstract public function getConfig(); + + abstract public function setConfig($config): void; +} diff --git a/src/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfig.php b/src/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfig.php index e2aa4ba1..ee2d8e6f 100644 --- a/src/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfig.php +++ b/src/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfig.php @@ -61,7 +61,7 @@ public function setIndividualRates(array $individualRates): void foreach ($individualRates as $individualRate) { if (!$individualRate instanceof HourlyIndividualRates) { throw new InvalidArgumentException( - 'Argument "individualRates" must contain only IndividualRates objects' + 'Argument "individualRates" must contain only HourlyIndividualRates objects' ); } } diff --git a/src/CrowdinApiClient/Model/HourlyUserReportSettingsTemplate.php b/src/CrowdinApiClient/Model/HourlyUserReportSettingsTemplate.php new file mode 100644 index 00000000..efd85ea1 --- /dev/null +++ b/src/CrowdinApiClient/Model/HourlyUserReportSettingsTemplate.php @@ -0,0 +1,60 @@ +id = (int)$this->getDataProperty('id'); + $this->name = (string)$this->getDataProperty('name'); + $this->currency = (string)$this->getDataProperty('currency'); + $this->config = new HourlyReportSettingsTemplateConfig($this->getDataProperty('config') ?? []); + $this->createdAt = (string)$this->getDataProperty('createdAt'); + $this->updatedAt = $this->getDataProperty('updatedAt') ? (string)$this->getDataProperty('updatedAt') : null; + } + + public function getConfig(): HourlyReportSettingsTemplateConfig + { + return $this->config; + } + + /** + * @param HourlyReportSettingsTemplateConfig $config + */ + public function setConfig($config): void + { + $this->config = $config; + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + 'id' => $this->id, + 'name' => $this->name, + 'currency' => $this->currency, + 'unit' => $this->unit, + 'config' => $this->config->toArray(), + 'createdAt' => $this->createdAt, + 'updatedAt' => $this->updatedAt, + ]; + } +} diff --git a/src/CrowdinApiClient/Model/UserReportSettingsTemplate.php b/src/CrowdinApiClient/Model/UserReportSettingsTemplate.php index ae262d15..c2bb9fb1 100644 --- a/src/CrowdinApiClient/Model/UserReportSettingsTemplate.php +++ b/src/CrowdinApiClient/Model/UserReportSettingsTemplate.php @@ -4,48 +4,20 @@ namespace CrowdinApiClient\Model; -use InvalidArgumentException; - -/** - * @package Crowdin\Model - */ -class UserReportSettingsTemplate extends BaseModel +class UserReportSettingsTemplate extends AbstractUserReportSettingsTemplate { - /** - * @var int - */ - protected $id; - - /** - * @var string - */ - protected $name; - - /** - * @var string - */ - protected $currency; - - /** - * @var string - */ - protected $unit; + public const SUPPORTED_UNITS = [ + Report::UNIT_STRINGS, + Report::UNIT_WORDS, + Report::UNIT_CHARS, + Report::UNIT_CHARS_WITH_SPACES, + ]; /** * @var ReportSettingsTemplateConfig */ protected $config; - /** - * @var string - */ - protected $createdAt; - - /** - * @var string|null - */ - protected $updatedAt; - public function __construct(array $data = []) { parent::__construct($data); @@ -54,105 +26,21 @@ public function __construct(array $data = []) $this->name = (string)$this->getDataProperty('name'); $this->currency = (string)$this->getDataProperty('currency'); $this->unit = (string)$this->getDataProperty('unit'); + $this->config = new ReportSettingsTemplateConfig($this->getDataProperty('config') ?? []); $this->createdAt = (string)$this->getDataProperty('createdAt'); $this->updatedAt = $this->getDataProperty('updatedAt') ? (string)$this->getDataProperty('updatedAt') : null; - - if ($this->unit === Report::UNIT_HOURS) { - $this->config = new HourlyReportSettingsTemplateConfig($this->getDataProperty('config') ?? []); - } else { - $this->config = new ReportSettingsTemplateConfig($this->getDataProperty('config') ?? []); - } } - public function getId(): int - { - return $this->id; - } - - public function getName(): string - { - return $this->name; - } - - public function setName(string $name): void - { - $this->name = $name; - } - - public function getCurrency(): string - { - return $this->currency; - } - - public function setCurrency(string $currency): void - { - if (!in_array($currency, Report::CURRENCIES, true)) { - throw new InvalidArgumentException( - sprintf( - 'Argument "currency" must be one of the following values: %s', - implode(', ', Report::CURRENCIES) - ) - ); - } - - $this->currency = $currency; - } - - public function getUnit(): string - { - return $this->unit; - } - - public function setUnit(string $unit): void - { - if (!in_array($unit, Report::UNITS, true)) { - throw new InvalidArgumentException( - sprintf( - 'Argument "unit" must be one of the following values: %s', - implode(', ', Report::UNITS) - ) - ); - } - - $this->unit = $unit; - } - - /** - * @return HourlyReportSettingsTemplateConfig|ReportSettingsTemplateConfig - */ - public function getConfig() + public function getConfig(): ReportSettingsTemplateConfig { return $this->config; } /** - * @param HourlyReportSettingsTemplateConfig|ReportSettingsTemplateConfig $config + * @param ReportSettingsTemplateConfig $config */ public function setConfig($config): void { $this->config = $config; } - - public function getCreatedAt(): string - { - return $this->createdAt; - } - - public function getUpdatedAt(): ?string - { - return $this->updatedAt; - } - - public function toArray(): array - { - return [ - 'id' => $this->id, - 'name' => $this->name, - 'currency' => $this->currency, - 'unit' => $this->unit, - 'config' => $this->config->toArray(), - 'createdAt' => $this->createdAt, - 'updatedAt' => $this->updatedAt, - ]; - } } diff --git a/tests/CrowdinApiClient/Api/UserApiTest.php b/tests/CrowdinApiClient/Api/UserApiTest.php index ef2be90d..4597591c 100644 --- a/tests/CrowdinApiClient/Api/UserApiTest.php +++ b/tests/CrowdinApiClient/Api/UserApiTest.php @@ -2,6 +2,8 @@ namespace CrowdinApiClient\Tests\Api; +use CrowdinApiClient\Model\HourlyReportSettingsTemplateConfig; +use CrowdinApiClient\Model\HourlyUserReportSettingsTemplate; use CrowdinApiClient\Model\ProjectMember; use CrowdinApiClient\Model\ProjectMemberAddedStatistics; use CrowdinApiClient\Model\ReportSettingsTemplateConfig; @@ -314,84 +316,135 @@ public function testDeleteMemberFromProject(): void $this->crowdin->user->deleteMemberFromProject(1, 1); } - public function testListReportsSettingsTemplates(): void + public function listReportsDataProvider(): array { - $this->mockRequestGet( - '/users/1/reports/settings-templates', - json_encode([ - 'data' => [ - [ - 'data' => [ - 'id' => 1, - 'name' => 'Default template', - 'currency' => 'USD', - 'unit' => 'words', - 'config' => [ - 'baseRates' => [ - 'fullTranslation' => 0.1, - 'proofread' => 0.12, - ], - 'individualRates' => [ - [ - 'languageIds' => ['uk'], - 'userIds' => [], + $pagination = [ + 'offset' => 0, + 'limit' => 25, + ]; + + return [ + 'userReportSettingsTemplate' => [ + 'requestData' => [ + 'data' => [ + [ + 'data' => [ + 'id' => 1, + 'name' => 'Default template', + 'currency' => 'USD', + 'unit' => 'words', + 'config' => [ + 'baseRates' => [ 'fullTranslation' => 0.1, 'proofread' => 0.12, ], - ], - 'netRateSchemes' => [ - 'tmMatch' => [ + 'individualRates' => [ [ - 'matchType' => '100', - 'price' => 0.1, + 'languageIds' => ['uk'], + 'userIds' => [], + 'fullTranslation' => 0.1, + 'proofread' => 0.12, ], ], - 'mtMatch' => [ - [ - 'matchType' => '100-82', - 'price' => 0.1, + 'netRateSchemes' => [ + 'tmMatch' => [ + [ + 'matchType' => '100', + 'price' => 0.1, + ], ], - ], - 'aiMatch' => [ - [ - 'matchType' => '100-74', - 'price' => 0.1, + 'mtMatch' => [ + [ + 'matchType' => '100-82', + 'price' => 0.1, + ], + ], + 'aiMatch' => [ + [ + 'matchType' => '100-74', + 'price' => 0.1, + ], + ], + 'suggestionMatch' => [ + [ + 'matchType' => 'perfect', + 'price' => 0.1, + ], ], ], - 'suggestionMatch' => [ + 'calculateInternalMatches' => false, + 'includePreTranslatedStrings' => false, + 'excludeApprovalsForEditedTranslations' => false, + 'preTranslatedStringsCategorizationAdjustment' => false, + ], + 'createdAt' => '2019-09-23T11:26:54+00:00', + 'updatedAt' => '2019-09-23T11:26:54+00:00', + ], + ], + ], + 'pagination' => $pagination, + ], + 'className' => UserReportSettingsTemplate::class, + 'configClassName' => ReportSettingsTemplateConfig::class, + ], + 'hourlyUserReportSettingsTemplate' => [ + 'requestData' => [ + 'data' => [ + [ + 'data' => [ + 'id' => 12, + 'name' => 'Hourly template', + 'currency' => 'USD', + 'unit' => 'hours', + 'config' => [ + 'baseRates' => [ + 'hourly' => 50.0, + ], + 'individualRates' => [ [ - 'matchType' => 'perfect', - 'price' => 0.1, + 'languageIds' => ['uk'], + 'userIds' => [8], + 'hourly' => 75.0, ], ], ], - 'calculateInternalMatches' => false, - 'includePreTranslatedStrings' => false, - 'excludeApprovalsForEditedTranslations' => false, - 'preTranslatedStringsCategorizationAdjustment' => false, + 'createdAt' => '2025-01-23T15:23:11+00:00', + 'updatedAt' => '2025-01-23T15:35:49+00:00', ], - 'createdAt' => '2019-09-23T11:26:54+00:00', - 'updatedAt' => '2019-09-23T11:26:54+00:00', ], ], + 'pagination' => $pagination, ], - 'pagination' => [ - 'offset' => 0, - 'limit' => 25, - ], - ]) + 'className' => HourlyUserReportSettingsTemplate::class, + 'configClassName' => HourlyReportSettingsTemplateConfig::class, + ], + ]; + } + + /** + * @dataProvider listReportsDataProvider + */ + public function testListReportsSettingsTemplates( + array $requestData, + string $className, + string $configClassName + ): void { + $this->mockRequestGet( + '/users/1/reports/settings-templates?limit=25&offset=0', + json_encode($requestData) ); - $templates = $this->crowdin->user->listReportSettingsTemplates(1); + $templates = $this->crowdin->user->listReportSettingsTemplates(1, ['limit' => 25, 'offset' => 0]); + $data = $requestData['data'][0]['data']; $this->assertInstanceOf(ModelCollection::class, $templates); $this->assertCount(1, $templates); - $this->assertInstanceOf(UserReportSettingsTemplate::class, $templates[0]); - $this->assertEquals(1, $templates[0]->getId()); - $this->assertEquals('Default template', $templates[0]->getName()); - $this->assertEquals('USD', $templates[0]->getCurrency()); - $this->assertEquals('words', $templates[0]->getUnit()); - $this->assertInstanceOf(ReportSettingsTemplateConfig::class, $templates[0]->getConfig()); + $this->assertInstanceOf($className, $templates[0]); + $this->assertEquals($data['id'], $templates[0]->getId()); + $this->assertEquals($data['name'], $templates[0]->getName()); + $this->assertEquals($data['currency'], $templates[0]->getCurrency()); + $this->assertEquals($data['unit'], $templates[0]->getUnit()); + $this->assertInstanceOf($configClassName, $templates[0]->getConfig()); } public function testCreateReportSettingsTemplate(): void @@ -470,73 +523,113 @@ public function testCreateReportSettingsTemplate(): void $this->assertEquals('USD', $template->getCurrency()); } - public function testGetReportSettingsTemplate(): void + public function getReportSettingsTemplateDataProvider(): array { - $this->mockRequestGet( - '/users/1/reports/settings-templates/1', - json_encode([ - 'data' => [ - 'id' => 1, - 'name' => 'Default template', - 'currency' => 'USD', - 'unit' => 'words', - 'config' => [ - 'baseRates' => [ - 'fullTranslation' => 0.1, - 'proofread' => 0.12, - ], - 'individualRates' => [ - [ - 'languageIds' => ['uk'], - 'userIds' => [], + return [ + 'userReportSettingsTemplate' => [ + 'requestData' => [ + 'data' => [ + 'id' => 1, + 'name' => 'Default template', + 'currency' => 'USD', + 'unit' => 'words', + 'config' => [ + 'baseRates' => [ 'fullTranslation' => 0.1, 'proofread' => 0.12, ], - ], - 'netRateSchemes' => [ - 'tmMatch' => [ + 'individualRates' => [ [ - 'matchType' => '100', - 'price' => 0.1, + 'languageIds' => ['uk'], + 'userIds' => [], + 'fullTranslation' => 0.1, + 'proofread' => 0.12, ], ], - 'mtMatch' => [ - [ - 'matchType' => '100-82', - 'price' => 0.1, + 'netRateSchemes' => [ + 'tmMatch' => [ + [ + 'matchType' => '100', + 'price' => 0.1, + ], ], - ], - 'aiMatch' => [ - [ - 'matchType' => '100-74', - 'price' => 0.1, + 'mtMatch' => [ + [ + 'matchType' => '100-82', + 'price' => 0.1, + ], + ], + 'aiMatch' => [ + [ + 'matchType' => '100-74', + 'price' => 0.1, + ], + ], + 'suggestionMatch' => [ + [ + 'matchType' => 'perfect', + 'price' => 0.1, + ], ], ], - 'suggestionMatch' => [ + 'calculateInternalMatches' => false, + 'includePreTranslatedStrings' => false, + 'excludeApprovalsForEditedTranslations' => false, + 'preTranslatedStringsCategorizationAdjustment' => false, + ], + 'createdAt' => '2019-09-23T11:26:54+00:00', + 'updatedAt' => '2019-09-23T11:26:54+00:00', + ], + ], + 'className' => UserReportSettingsTemplate::class, + 'configClassName' => ReportSettingsTemplateConfig::class, + ], + 'hourlyUserReportSettingsTemplate' => [ + 'requestData' => [ + 'data' => [ + 'id' => 12, + 'name' => 'Hourly template', + 'currency' => 'USD', + 'unit' => 'hours', + 'config' => [ + 'baseRates' => [ + 'hourly' => 50.0, + ], + 'individualRates' => [ [ - 'matchType' => 'perfect', - 'price' => 0.1, + 'languageIds' => ['uk'], + 'userIds' => [8], + 'hourly' => 75.0, ], ], ], - 'calculateInternalMatches' => false, - 'includePreTranslatedStrings' => false, - 'excludeApprovalsForEditedTranslations' => false, - 'preTranslatedStringsCategorizationAdjustment' => false, + 'createdAt' => '2025-01-23T15:23:11+00:00', + 'updatedAt' => '2025-01-23T15:35:49+00:00', ], - 'createdAt' => '2019-09-23T11:26:54+00:00', - 'updatedAt' => '2019-09-23T11:26:54+00:00', ], - ]) + 'className' => HourlyUserReportSettingsTemplate::class, + 'configClassName' => HourlyReportSettingsTemplateConfig::class, + ], + ]; + } + + /** + * @dataProvider getReportSettingsTemplateDataProvider + */ + public function testGetReportSettingsTemplate(array $requestData, string $className, string $configClassName): void + { + $this->mockRequestGet( + '/users/1/reports/settings-templates/1', + json_encode($requestData) ); $template = $this->crowdin->user->getReportSettingsTemplate(1, 1); - $this->assertInstanceOf(UserReportSettingsTemplate::class, $template); - $this->assertEquals(1, $template->getId()); - $this->assertEquals('Default template', $template->getName()); - $this->assertEquals('USD', $template->getCurrency()); - $this->assertInstanceOf(ReportSettingsTemplateConfig::class, $template->getConfig()); + $this->assertInstanceOf($className, $template); + $this->assertEquals($requestData['data']['id'], $template->getId()); + $this->assertEquals($requestData['data']['name'], $template->getName()); + $this->assertEquals($requestData['data']['currency'], $template->getCurrency()); + $this->assertInstanceOf($configClassName, $template->getConfig()); } public function testDeleteReportSettingsTemplate(): void diff --git a/tests/CrowdinApiClient/Model/HourlyIndividualRatesTest.php b/tests/CrowdinApiClient/Model/HourlyIndividualRatesTest.php index 2f4e664d..e772e776 100644 --- a/tests/CrowdinApiClient/Model/HourlyIndividualRatesTest.php +++ b/tests/CrowdinApiClient/Model/HourlyIndividualRatesTest.php @@ -70,7 +70,7 @@ public function languageIdsExceptionDataProvider(): array /** * @dataProvider languageIdsExceptionDataProvider */ - public function testSetLanguageIdsEmptyThrowsException(array $languageIds, string $exceptionMessage): void + public function testSetLanguageIdsException(array $languageIds, string $exceptionMessage): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage($exceptionMessage); diff --git a/tests/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfigTest.php b/tests/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfigTest.php index ce91ecb9..3bd23f01 100644 --- a/tests/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfigTest.php +++ b/tests/CrowdinApiClient/Model/HourlyReportSettingsTemplateConfigTest.php @@ -46,11 +46,9 @@ public function testSetData(): void $baseRates = new HourlyBaseRates(['hourly' => 0.2]); $individualRates = [ new HourlyIndividualRates([ - [ - 'languageIds' => ['uk', 'en', 'jp'], - 'userIds' => [8], - 'hourly' => 0.3, - ], + 'languageIds' => ['uk', 'en', 'jp'], + 'userIds' => [8], + 'hourly' => 0.3, ]), ]; @@ -83,7 +81,7 @@ public function individualRatesExceptionDataProvider(): array 'individualRates' => [ [], ], - 'exceptionMessage' => 'Argument "individualRates" must contain only IndividualRates objects', + 'exceptionMessage' => 'Argument "individualRates" must contain only HourlyIndividualRates objects', ], ]; } diff --git a/tests/CrowdinApiClient/Model/HourlyUserReportSettingsTemplateTest.php b/tests/CrowdinApiClient/Model/HourlyUserReportSettingsTemplateTest.php new file mode 100644 index 00000000..d15d13ea --- /dev/null +++ b/tests/CrowdinApiClient/Model/HourlyUserReportSettingsTemplateTest.php @@ -0,0 +1,97 @@ + 12, + 'name' => 'Hourly template', + 'currency' => 'USD', + 'unit' => 'hours', + 'config' => [ + 'baseRates' => [ + 'hourly' => 50.0, + ], + 'individualRates' => [ + [ + 'languageIds' => ['uk'], + 'userIds' => [8], + 'hourly' => 75.0, + ], + ], + ], + 'createdAt' => '2025-01-23T15:23:11+00:00', + 'updatedAt' => '2025-01-23T15:35:49+00:00', + ]; + + public function testLoadData(): void + { + $template = new HourlyUserReportSettingsTemplate($this->data); + + $this->assertEquals($this->data['id'], $template->getId()); + $this->assertEquals($this->data['name'], $template->getName()); + $this->assertEquals($this->data['currency'], $template->getCurrency()); + $this->assertEquals($this->data['unit'], $template->getUnit()); + $this->assertInstanceOf(HourlyReportSettingsTemplateConfig::class, $template->getConfig()); + $this->assertEquals( + $this->data['config']['baseRates']['hourly'], + $template->getConfig()->getBaseRates()->getHourly() + ); + $this->assertEquals($this->data['createdAt'], $template->getCreatedAt()); + $this->assertEquals($this->data['updatedAt'], $template->getUpdatedAt()); + } + + public function testSetData(): void + { + $template = new HourlyUserReportSettingsTemplate($this->data); + + $name = 'New name'; + $currency = 'UAH'; + $unit = 'hours'; + $hourly = 100.0; + + $config = $template->getConfig(); + $config->setBaseRates(new HourlyBaseRates(['hourly' => $hourly])); + + $template->setName($name); + $template->setCurrency($currency); + $template->setUnit($unit); + $template->setConfig($config); + + $this->assertEquals($name, $template->getName()); + $this->assertEquals($currency, $template->getCurrency()); + $this->assertEquals($unit, $template->getUnit()); + $this->assertEquals($hourly, $template->getConfig()->getBaseRates()->getHourly()); + } + + public function testSetInvalidCurrency(): void + { + $this->expectException(InvalidArgumentException::class); + + $template = new HourlyUserReportSettingsTemplate($this->data); + $template->setCurrency('INVALID'); + } + + public function testSetInvalidUnit(): void + { + $this->expectException(InvalidArgumentException::class); + + $template = new HourlyUserReportSettingsTemplate($this->data); + $template->setUnit(Report::UNIT_WORDS); + } + + public function testToArray(): void + { + $this->assertEquals($this->data, (new HourlyUserReportSettingsTemplate($this->data))->toArray()); + } +} diff --git a/tests/CrowdinApiClient/Model/UserReportSettingsTemplateTest.php b/tests/CrowdinApiClient/Model/UserReportSettingsTemplateTest.php index 84d127e7..5fc5869b 100644 --- a/tests/CrowdinApiClient/Model/UserReportSettingsTemplateTest.php +++ b/tests/CrowdinApiClient/Model/UserReportSettingsTemplateTest.php @@ -4,7 +4,6 @@ namespace CrowdinApiClient\Tests\Model; -use CrowdinApiClient\Model\HourlyReportSettingsTemplateConfig; use CrowdinApiClient\Model\ReportSettingsTemplateConfig; use CrowdinApiClient\Model\UserReportSettingsTemplate; use InvalidArgumentException; @@ -69,54 +68,18 @@ class UserReportSettingsTemplateTest extends TestCase 'updatedAt' => '2025-01-23T15:35:49+00:00', ]; - public function userReportSettingsTemplateDataProvider(): array + public function testLoadData(): void { - return [ - 'userReportSettingsTemplateForPostEditing' => [ - 'data' => $this->data, - 'expectedConfigClass' => ReportSettingsTemplateConfig::class, - ], - 'userReportSettingsTemplateForHours' => [ - 'data' => [ - 'id' => 12, - 'name' => 'Default template', - 'currency' => 'UAH', - 'unit' => 'hours', - 'config' => [ - 'baseRates' => [ - 'hourly' => 0.1, - ], - 'individualRates' => [ - [ - 'languageIds' => ['uk'], - 'userIds' => [8], - 'hourly' => 0.1, - ], - ], - ], - 'createdAt' => '2025-01-23T15:23:11+00:00', - 'updatedAt' => '2025-01-23T15:35:49+00:00', - ], - 'expectedConfigClass' => HourlyReportSettingsTemplateConfig::class, - ], - ]; - } - - /** - * @dataProvider userReportSettingsTemplateDataProvider - */ - public function testLoadData(array $data, string $expectedConfigClass): void - { - $template = new UserReportSettingsTemplate($data); + $template = new UserReportSettingsTemplate($this->data); - $this->assertEquals($data['id'], $template->getId()); - $this->assertEquals($data['name'], $template->getName()); - $this->assertEquals($data['currency'], $template->getCurrency()); - $this->assertEquals($data['unit'], $template->getUnit()); - $this->assertInstanceOf($expectedConfigClass, $template->getConfig()); - $this->assertEquals($data['config'], $template->getConfig()->toArray()); - $this->assertEquals($data['createdAt'], $template->getCreatedAt()); - $this->assertEquals($data['updatedAt'], $template->getUpdatedAt()); + $this->assertEquals($this->data['id'], $template->getId()); + $this->assertEquals($this->data['name'], $template->getName()); + $this->assertEquals($this->data['currency'], $template->getCurrency()); + $this->assertEquals($this->data['unit'], $template->getUnit()); + $this->assertInstanceOf(ReportSettingsTemplateConfig::class, $template->getConfig()); + $this->assertEquals($this->data['config'], $template->getConfig()->toArray()); + $this->assertEquals($this->data['createdAt'], $template->getCreatedAt()); + $this->assertEquals($this->data['updatedAt'], $template->getUpdatedAt()); } public function testSetData(): void