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