Fixes for 1.12 (#4655)

* fix missing locales
* bump composer packages
* changed translations
* assert timezone on customer
* include user accountNumber in excel export
* improve next customer number calculation
* fix z-index of contextmenu / action dropdown
This commit is contained in:
Kevin Papst
2024-02-22 13:03:09 +01:00
committed by GitHub
parent 36c578452e
commit f016221e8e
28 changed files with 892 additions and 210 deletions

View File

@@ -168,12 +168,14 @@ final class RegenerateLocalesCommand extends Command
$removableDuplicates[] = $locale;
}
$io->title('Redundant locales that will be skipped');
/*
$io->title('Redundant locales that could be skipped');
$io->writeln(implode('|', $removableDuplicates));
foreach ($removableDuplicates as $duplicate) {
unset($appLocales[$duplicate]);
}
*/
// in the future this list should be reduced to the list of available translations, but for a long time users
// could choose from the entire list of all locales, so we likely have to keep that forever ...

View File

@@ -28,9 +28,9 @@ use Symfony\Component\Security\Http\LoginLink\LoginLinkHandlerInterface;
final class UserLoginLinkCommand extends Command
{
public function __construct(
private LoginLinkHandlerInterface $loginLink,
private UserRepository $userRepository,
private RequestStack $requestStack
private readonly LoginLinkHandlerInterface $loginLink,
private readonly UserRepository $userRepository,
private readonly RequestStack $requestStack
)
{
parent::__construct();

View File

@@ -28,10 +28,10 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
final class CustomerService
{
public function __construct(
private CustomerRepository $repository,
private SystemConfiguration $configuration,
private ValidatorInterface $validator,
private EventDispatcherInterface $dispatcher
private readonly CustomerRepository $repository,
private readonly SystemConfiguration $configuration,
private readonly ValidatorInterface $validator,
private readonly EventDispatcherInterface $dispatcher
) {
}
@@ -74,7 +74,6 @@ final class CustomerService
}
/**
* @param Customer $customer
* @param string[] $groups
* @throws ValidationFailedException
*/
@@ -122,15 +121,28 @@ final class CustomerService
}
public function calculateNextCustomerNumber(): string
{
// we cannot use max(number) because a varchar column returns unexpected results
$start = $this->repository->countCustomer();
do {
$number = $this->getNextNumber($start++);
$customer = $this->findCustomerByNumber($number);
} while ($customer !== null);
return $number;
}
private function getNextNumber(int $counter): string
{
$format = $this->configuration->find('customer.number_format');
if (empty($format) || !\is_string($format)) {
$format = '{cc,4}';
}
$numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy): string|int {
$numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($counter): string|int {
return match ($format) {
'cc' => $this->repository->count([]) + $increaseBy,
'cc' => $counter + $increaseBy,
default => $originalFormat,
};
});

View File

@@ -146,6 +146,7 @@ class Customer implements EntityWithMetaFields, EntityWithBudget
*/
#[ORM\Column(name: 'timezone', type: 'string', length: 64, nullable: false)]
#[Assert\NotBlank]
#[Assert\Timezone]
#[Assert\Length(max: 64)]
#[Serializer\Expose]
#[Serializer\Groups(['Customer_Entity'])]

View File

@@ -80,6 +80,9 @@ abstract class AbstractSpreadsheetRenderer
'label' => 'name'
],
'username' => [],
'accountNumber' => [
'label' => 'account_number'
],
'customer' => [],
'project' => [],
'activity' => [],
@@ -315,6 +318,18 @@ abstract class AbstractSpreadsheetRenderer
}
}
if (isset($columns['accountNumber'])) {
if (!isset($columns['accountNumber']['render'])) {
$columns['accountNumber']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$accountNumber = '';
if (null !== $entity->getUser()) {
$accountNumber = $entity->getUser()->getAccountNumber();
}
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $accountNumber);
};
}
}
if (isset($columns['customer']) && !isset($columns['customer']['render'])) {
$columns['customer']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$customer = '';

View File

@@ -45,11 +45,11 @@ use Psr\EventDispatcher\EventDispatcherInterface;
class ProjectStatisticService
{
public function __construct(
private ProjectRepository $projectRepository,
private ActivityRepository $activityRepository,
private TimesheetRepository $timesheetRepository,
private EventDispatcherInterface $dispatcher,
private UserRepository $userRepository
private readonly ProjectRepository $projectRepository,
private readonly ActivityRepository $activityRepository,
private readonly TimesheetRepository $timesheetRepository,
private readonly EventDispatcherInterface $dispatcher,
private readonly UserRepository $userRepository
)
{
}
@@ -729,7 +729,7 @@ class ProjectStatisticService
->addSelect('COALESCE(SUM(t.rate), 0) AS rate')
->andWhere($tplQb->expr()->in('t.project', ':project'))
->groupBy('t.project')
->setParameter('project', array_values($projectIds))
->setParameter('project', $projectIds)
;
// find the most recent timesheet for each project

View File

@@ -29,7 +29,7 @@ use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder;
/**
* @extends \Doctrine\ORM\EntityRepository<Customer>
* @extends EntityRepository<Customer>
*/
class CustomerRepository extends EntityRepository
{
@@ -75,7 +75,7 @@ class CustomerRepository extends EntityRepository
return $this->count([]);
}
private function addPermissionCriteria(QueryBuilder $qb, ?User $user = null, array $teams = [])
private function addPermissionCriteria(QueryBuilder $qb, ?User $user = null, array $teams = []): void
{
$permissions = $this->getPermissionCriteria($qb, $user, $teams);
if ($permissions->count() > 0) {
@@ -249,7 +249,6 @@ class CustomerRepository extends EntityRepository
}
/**
* @param CustomerQuery $query
* @return Customer[]
*/
public function getCustomersForQuery(CustomerQuery $query): iterable
@@ -261,12 +260,7 @@ class CustomerRepository extends EntityRepository
return $paginator->getAll();
}
/**
* @param Customer $delete
* @param Customer|null $replace
* @throws \Doctrine\ORM\Exception\ORMException
*/
public function deleteCustomer(Customer $delete, ?Customer $replace = null)
public function deleteCustomer(Customer $delete, ?Customer $replace = null): void
{
$em = $this->getEntityManager();
$em->beginTransaction();
@@ -308,14 +302,14 @@ class CustomerRepository extends EntityRepository
return $qb->getQuery()->getResult();
}
public function saveComment(CustomerComment $comment)
public function saveComment(CustomerComment $comment): void
{
$entityManager = $this->getEntityManager();
$entityManager->persist($comment);
$entityManager->flush();
}
public function deleteComment(CustomerComment $comment)
public function deleteComment(CustomerComment $comment): void
{
$entityManager = $this->getEntityManager();
$entityManager->remove($comment);

View File

@@ -100,7 +100,7 @@ final class WorkingTimeService
return $year->getMonth($monthDate);
}
public function approveMonth(User $user, Month $month, \DateTimeInterface $approvalDate, User $approver): void
public function approveMonth(User $user, Month $month, \DateTimeInterface $approvalDate, User $approvedBy): void
{
foreach ($month->getDays() as $day) {
$workingTime = $day->getWorkingTime();
@@ -116,7 +116,7 @@ final class WorkingTimeService
continue;
}
$workingTime->setApprovedBy($approver);
$workingTime->setApprovedBy($approvedBy);
// FIXME see calling method
$workingTime->setApprovedAt(\DateTimeImmutable::createFromInterface($approvalDate));
$this->workingTimeRepository->scheduleWorkingTimeUpdate($workingTime);
@@ -124,7 +124,7 @@ final class WorkingTimeService
$this->workingTimeRepository->persistScheduledWorkingTimes();
$this->eventDispatcher->dispatch(new WorkingTimeApproveMonthEvent($user, $month, $approvalDate, $approver));
$this->eventDispatcher->dispatch(new WorkingTimeApproveMonthEvent($user, $month, $approvalDate, $approvedBy));
}
/**