diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ab2b42f..da92c479 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,14 +8,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [1.1.1] - 2023-12-18 +* Changed how project billing is put on record, to allow for finishing a partially +complete process. +* Added exported date to invoices overview. + +## [1.1.1] * Added choices.js to dropdowns with many options. * Added epic filter to worklog selection page. * Removed time from period selections on worklog selection page. * Optimized sync memory usage. -## [1.1.0] - 2023-12-14 +## [1.1.0] * Updated api source to use Leantime * Modified getPlanningData to work with Leantime data @@ -39,21 +43,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0.2] -### Changed - * Updated package-lock.json. ## [1.0.1] -### Changed - * Updated openid-connect to newest version. * Updated docker-compose files to newest version. ## [1.0.0] -### Added - * Added Billing. * Added migration path from JiraEconomics. * Added Sprint Report. @@ -66,9 +64,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added help text to invoice entry (worklog) type. * Added publiccode.yml * Added OpenID Connect Controller - -### Changed - * Updated docker files to the newest version. * Fixed path bugs. * Added filtering to lists. @@ -92,6 +87,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Changed worklog save button styling to be sticky. [Unreleased]: https://github.com/itk-dev/economics/compare/1.1.0...HEAD +[1.1.1]: https://github.com/itk-dev/economics/compare/1.1.0...1.1.1 [1.1.0]: https://github.com/itk-dev/economics/compare/1.0.4...1.1.0 [1.0.4]: https://github.com/itk-dev/economics/compare/1.0.3...1.0.4 [1.0.3]: https://github.com/itk-dev/economics/compare/1.0.2...1.0.3 diff --git a/src/Entity/Invoice.php b/src/Entity/Invoice.php index 3bb20ad3..4aac1eec 100644 --- a/src/Entity/Invoice.php +++ b/src/Entity/Invoice.php @@ -76,7 +76,7 @@ class Invoice #[ORM\ManyToOne(inversedBy: 'invoices')] private ?Project $project = null; - #[ORM\ManyToOne(inversedBy: 'invoices')] + #[ORM\ManyToOne(fetch: 'EAGER', inversedBy: 'invoices')] private ?Client $client = null; #[ORM\Column(nullable: true)] diff --git a/src/Exception/InvoiceAlreadyOnRecordException.php b/src/Exception/InvoiceAlreadyOnRecordException.php new file mode 100644 index 00000000..9e787e48 --- /dev/null +++ b/src/Exception/InvoiceAlreadyOnRecordException.php @@ -0,0 +1,8 @@ +orderBy('p.name', 'ASC'); }, ]) - ->add('periodStart', DateTimeType::class, [ + ->add('periodStart', DateType::class, [ 'required' => true, 'label' => 'project_billing.field_period_start', 'label_attr' => ['class' => 'label'], @@ -46,7 +47,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void 'html5' => true, 'attr' => ['class' => 'form-element'], ]) - ->add('periodEnd', DateTimeType::class, [ + ->add('periodEnd', DateType::class, [ 'required' => true, 'label' => 'project_billing.field_period_end', 'label_attr' => ['class' => 'label'], diff --git a/src/Service/BillingService.php b/src/Service/BillingService.php index fbbf51db..e7105038 100644 --- a/src/Service/BillingService.php +++ b/src/Service/BillingService.php @@ -12,6 +12,7 @@ use App\Entity\Worklog; use App\Enum\ClientTypeEnum; use App\Enum\InvoiceEntryTypeEnum; +use App\Exception\InvoiceAlreadyOnRecordException; use App\Repository\AccountRepository; use App\Repository\ClientRepository; use App\Repository\InvoiceEntryRepository; @@ -369,17 +370,17 @@ public function syncProjects(callable $progressCallback): void /** * @throws \Exception */ - public function recordInvoice(Invoice $invoice): void + public function recordInvoice(Invoice $invoice, bool $flush = true): void { - // Make sure client is set. - $errors = $this->getInvoiceRecordableErrors($invoice); - if ($invoice->isRecorded()) { - throw new \Exception('Already recorded.'); + throw new InvoiceAlreadyOnRecordException('Invoice is already on record.'); } + // Make sure client is set. + $errors = $this->getInvoiceRecordableErrors($invoice); + if (!empty($errors)) { - throw new \Exception('Cannot record invoices. Errors not handled.'); + throw new \Exception('Cannot record invoice ' . $invoice->getName() .'('. $invoice->getId().'). Errors not handled: ' . json_encode($errors)); } $client = $invoice->getClient(); @@ -408,7 +409,7 @@ public function recordInvoice(Invoice $invoice): void } } - $this->invoiceRepository->save($invoice, true); + $this->invoiceRepository->save($invoice, $flush); } // TODO: Replace with exceptions. diff --git a/src/Service/ProjectBillingService.php b/src/Service/ProjectBillingService.php index 920af495..d08a337c 100644 --- a/src/Service/ProjectBillingService.php +++ b/src/Service/ProjectBillingService.php @@ -11,6 +11,7 @@ use App\Enum\ClientTypeEnum; use App\Enum\InvoiceEntryTypeEnum; use App\Enum\MaterialNumberEnum; +use App\Exception\InvoiceAlreadyOnRecordException; use App\Repository\AccountRepository; use App\Repository\ClientRepository; use App\Repository\IssueRepository; @@ -208,9 +209,16 @@ public function createProjectBilling(int $projectBillingId): void public function recordProjectBilling(ProjectBilling $projectBilling): void { foreach ($projectBilling->getInvoices() as $invoice) { - $this->billingService->recordInvoice($invoice); + try { + $this->billingService->recordInvoice($invoice, false); + } catch (InvoiceAlreadyOnRecordException) { + // Ignore if invoice is already on record. + } } + // Persist the changes to invoices. + $this->entityManager->flush(); + $projectBilling->setRecorded(true); $this->projectBillingRepository->save($projectBilling, true); } diff --git a/templates/invoices/index.html.twig b/templates/invoices/index.html.twig index db3e606d..05189c05 100644 --- a/templates/invoices/index.html.twig +++ b/templates/invoices/index.html.twig @@ -17,7 +17,7 @@ {{ form_end(form) }} {% set recordedInvoices = invoiceFilterData.recorded %} - {% set numberOfColumns = recordedInvoices ? 8 : 7 %} + {% set numberOfColumns = recordedInvoices ? 9 : 7 %}
@@ -37,6 +37,9 @@ {{ knp_pagination_sortable(invoices, 'invoices.list_created_by'|trans, 'invoice.createdBy') }} {{ knp_pagination_sortable(invoices, 'invoices.list_updated_at'|trans, 'invoice.updatedAt') }} {{ 'invoices.list_total_price'|trans }} + {% if recordedInvoices %} + {{ knp_pagination_sortable(invoices, 'invoices.list_exported_date'|trans, 'invoice.exportedDate') }} + {% endif %} {{ 'invoices.list_actions'|trans }} @@ -64,9 +67,17 @@ {{ invoice.createdBy }} {{ invoice.updatedAt ? invoice.updatedAt|date('Y-m-d') : '' }} {{ invoice.totalPrice }} + {% if recordedInvoices %} + {{ invoice.exportedDate ? invoice.exportedDate|date('Y-m-d') : '' }} + {% endif %} - {{ 'invoices.action_edit'|trans }} + + {% if recordedInvoices %} + {{ 'invoices.action_view'|trans }} + {% else %} + {{ 'invoices.action_edit'|trans }} + {% endif %} + {% endfor %} diff --git a/translations/messages.da.yaml b/translations/messages.da.yaml index 85478f2f..06d4c074 100644 --- a/translations/messages.da.yaml +++ b/translations/messages.da.yaml @@ -224,6 +224,8 @@ invoices: list_recorded: 'Bogført' export_only_available_when_mandatory_fields_are_set: 'Eksport kun muligt når der er sat en kundekonto' action_export_selected: 'Eksporter valg' + action_view: 'Se' + list_exported_date: 'Eksportdato' material_number_enum: internal: "Interne: 103361"