Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions app/Application/ProjectService.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\DB;
use InvoiceShelf\Modules\Contracts\Host\CompanyDataReader;
use Modules\TasksProjects\Application\Exceptions\ProjectInUse;
use Modules\TasksProjects\Models\Project;
use Modules\TasksProjects\Models\ProjectMember;
Expand All @@ -23,6 +24,8 @@ final class ProjectService
'currency_id', 'default_rate', 'budget_minutes', 'due_date', 'creator_id',
];

public function __construct(private readonly CompanyDataReader $companyData) {}

/**
* @param array{status?: string, customer_id?: int, user_id?: int, search?: string} $filters
* @return Collection<int, Project>
Expand Down Expand Up @@ -68,7 +71,12 @@ public function findForCompany(int $companyId, int $id): Project
return $project;
}

/** @param array<string, mixed> $attributes */
/**
* A project's currency follows the customer it was filed under, unless the
* caller named one itself.
*
* @param array<string, mixed> $attributes
*/
public function create(int $companyId, array $attributes): Project
{
$values = ['company_id' => $companyId, 'status' => Project::STATUS_ACTIVE];
Expand All @@ -79,12 +87,21 @@ public function create(int $companyId, array $attributes): Project
}
}

if (! array_key_exists('currency_id', $attributes)) {
$currencyId = $this->customerCurrency($companyId, $values['customer_id'] ?? null);

if ($currencyId !== null) {
$values['currency_id'] = $currencyId;
}
}

return Project::query()->create($values);
}

/**
* A project's customer is denormalised onto its tasks, so changing it
* rewrites the tasks that follow the project.
* rewrites the tasks that follow the project, and moves the project to
* that customer's currency unless the caller named one itself.
*
* @param array<string, mixed> $attributes
*/
Expand All @@ -101,6 +118,14 @@ public function update(int $companyId, int $id, array $attributes): Project
}
}

if (! array_key_exists('currency_id', $attributes) && array_key_exists('customer_id', $attributes)) {
$currencyId = $this->customerCurrency($companyId, $project->customer_id);

if ($currencyId !== null) {
$project->currency_id = $currencyId;
}
}

$project->save();

if ($customerChanged) {
Expand Down Expand Up @@ -207,6 +232,23 @@ public function totals(Project $project): array
];
}

/**
* The currency of one customer, read through the host contract.
*
* An internal project has no customer and so no currency to inherit, and a
* customer without one leaves the project's currency alone.
*/
private function customerCurrency(int $companyId, mixed $customerId): ?int
{
if ($customerId === null) {
return null;
}

$currencyId = $this->companyData->findCustomer($companyId, (int) $customerId)['currency_id'] ?? null;

return $currencyId === null ? null : (int) $currencyId;
}

private function setStatus(int $companyId, int $id, string $status): Project
{
$project = $this->findForCompany($companyId, $id);
Expand Down
Loading
Loading