diff --git a/src/components/InvoiceButton/invoice_button.latte b/src/components/InvoiceButton/invoice_button.latte index 6e290ce..1c933f6 100644 --- a/src/components/InvoiceButton/invoice_button.latte +++ b/src/components/InvoiceButton/invoice_button.latte @@ -1,6 +1,17 @@ {if $admin} {if $payment->invoice} - {_invoices.frontend.invoice_button.download} +
+ + +
+ {elseif $payment->paid_at && $payment->paid_at->diff(new \DateTime())->days > $canGenerateDaysLimit} {_invoices.frontend.invoice_button.not_available_anymore} {elseif $paymentInvoicable} diff --git a/src/config/config.neon b/src/config/config.neon index cd3e893..de6ced4 100644 --- a/src/config/config.neon +++ b/src/config/config.neon @@ -32,6 +32,8 @@ services: - Crm\InvoicesModule\Events\NewAddressHandler - Crm\InvoicesModule\Events\PaymentStatusChangeHandler - Crm\InvoicesModule\Forms\ChangeInvoiceDetailsFormFactory + - Crm\InvoicesModule\Forms\ChangeInvoiceFormFactory + - Crm\InvoicesModule\Forms\ChangeInvoiceItemsFormFactory - Crm\InvoicesModule\Forms\UserInvoiceFormFactory - Crm\InvoicesModule\Gateways\ProformaInvoice - Crm\InvoicesModule\Hermes\ZipInvoicesHandler diff --git a/src/forms/ChangeInvoiceFormFactory.php b/src/forms/ChangeInvoiceFormFactory.php new file mode 100644 index 0000000..95aeceb --- /dev/null +++ b/src/forms/ChangeInvoiceFormFactory.php @@ -0,0 +1,101 @@ +translator = $translator; + $this->invoicesRepository = $invoicesRepository; + $this->dataProviderManager = $dataProviderManager; + $this->countriesRepository = $countriesRepository; + } + + /** + * @param int $id + * @return Form + */ + public function create(int $id) + { + $form = new Form; + $form->setRenderer(new BootstrapRenderer()); + $form->addProtection(); + + $form->addHidden('invoice_id', $id); + + $form->addText('buyer_name', $this->translator->translate('invoices.form.invoice.label.company_name')) + ->setAttribute('placeholder', $this->translator->translate('invoices.form.invoice.placeholder.company_name')); + + $form->addText('buyer_address', $this->translator->translate('invoices.form.invoice.label.address')) + ->setAttribute('placeholder', $this->translator->translate('invoices.form.invoice.placeholder.address')); + + $form->addText('buyer_city', $this->translator->translate('invoices.form.invoice.label.city')) + ->setAttribute('placeholder', $this->translator->translate('invoices.form.invoice.placeholder.city')); + + $form->addText('buyer_zip', $this->translator->translate('invoices.form.invoice.label.zip')) + ->setAttribute('placeholder', $this->translator->translate('invoices.form.invoice.placeholder.zip')); + + $form->addSelect('country_id', $this->translator->translate('invoices.form.invoice.label.country_id'), $this->countriesRepository->getAllPairs()); + + $form->addText('company_id', $this->translator->translate('invoices.form.invoice.label.company_id')) + ->setAttribute('placeholder', $this->translator->translate('invoices.form.invoice.placeholder.company_id')); + + $form->addText('company_tax_id', $this->translator->translate('invoices.form.invoice.label.company_tax_id')) + ->setAttribute('placeholder', $this->translator->translate('invoices.form.invoice.placeholder.company_tax_id')); + + $form->addText('company_vat_id', $this->translator->translate('invoices.form.invoice.label.company_vat_id')) + ->setAttribute('placeholder', $this->translator->translate('invoices.form.invoice.placeholder.company_vat_id')); + + /** @var AddressFormDataProviderInterface $providers */ + $providers = $this->dataProviderManager->getProviders('invoices.dataprovider.invoice_form', AddressFormDataProviderInterface::class); + foreach ($providers as $sorting => $provider) { + $form = $provider->provide(['form' => $form, 'addressType' => 'invoice']); + } + + $form->addSubmit('send', $this->translator->translate('invoices.form.invoice.label.send')); + + $form->onSuccess[] = [$this, 'formSucceeded']; + return $form; + } + + public function formSucceeded($form, $values) + { + $invoice = $this->invoicesRepository->find($values->invoice_id); + + $this->invoicesRepository->update($invoice, [ + 'buyer_name' => $values->buyer_name, + 'buyer_address' => $values->buyer_address, + 'buyer_city' => $values->buyer_city, + 'buyer_zip' => $values->buyer_zip, + 'buyer_country_id' => $values->country_id, + 'buyer_id' => $values->company_id, + 'buyer_tax_id' => $values->company_tax_id, + 'buyer_vat_id' => $values->company_vat_id + ]); + + $this->onSuccess->__invoke($form); + } +} diff --git a/src/forms/ChangeInvoiceItemsFormFactory.php b/src/forms/ChangeInvoiceItemsFormFactory.php new file mode 100644 index 0000000..26643fe --- /dev/null +++ b/src/forms/ChangeInvoiceItemsFormFactory.php @@ -0,0 +1,93 @@ +translator = $translator; + $this->invoicesRepository = $invoicesRepository; + $this->invoiceItemsRepository = $invoiceItemsRepository; + } + + /** + * @param int $id + * @return Form + */ + public function create(int $id) + { + $invoiceItems = null; + $invoice = $this->invoicesRepository->find($id); + if ($invoice) { + $invoiceItems = $invoice->related('invoice_items'); + } + + $form = new Form; + $form->setRenderer(new BootstrapRenderer()); + $form->addProtection(); + $defaults = []; + + $items = $form->addContainer('items'); + $i = 1; + foreach ($invoiceItems as $item) { + $itemName = "item_" . $item->id; + + $items->addTextArea($itemName, $this->translator->translate('invoices.form.change_invoice_items.item', ['i' => $i++])) + ->setAttribute('placeholder', $this->translator->translate('invoices.form.change_invoice_items.placeholder')) + ->setAttribute('class', 'simple-editor') + ->setAttribute('rows', 2) + ->setAttribute( + 'data-html-editor', + ['btns' => [ + ['viewHTML'], + ['undo', 'redo'], + ['formatting'], + ['strong', 'em', 'del'] + ]] + ); + + $defaults['items'][$itemName] = $item->text; + } + + $form->addSubmit('send', $this->translator->translate('invoices.frontend.change_invoice_details.submit')); + + $form->setDefaults($defaults); + + $form->onSuccess[] = [$this, 'formSucceeded']; + return $form; + } + + public function formSucceeded($form, $values) + { + $items = $values['items']; + foreach ($items as $key => $value) { + $itemId = explode('_', $key)[1]; + $invoiceItem = $this->invoiceItemsRepository->find($itemId); + + $this->invoiceItemsRepository->update($invoiceItem, [ + 'text' => $value + ]); + } + + $this->onSuccess->__invoke($form); + } +} diff --git a/src/forms/UserInvoiceFormFactory.php b/src/forms/UserInvoiceFormFactory.php index 5887547..dc87a4c 100644 --- a/src/forms/UserInvoiceFormFactory.php +++ b/src/forms/UserInvoiceFormFactory.php @@ -80,15 +80,15 @@ public function create(ActiveRow $payment): Form $form->addText('zip', 'invoices.form.invoice.label.zip') ->setAttribute('placeholder', 'invoices.form.invoice.placeholder.zip') ->setRequired('invoices.form.invoice.required.zip'); - $form->addText('company_id', 'invoices.form.invoice.label.ico') - ->setAttribute('placeholder', 'invoices.form.invoice.placeholder.ico'); - $form->addText('company_tax_id', 'invoices.form.invoice.label.dic') - ->setAttribute('placeholder', 'invoices.form.invoice.placeholder.dic'); - $form->addText('company_vat_id', 'invoices.form.invoice.label.icdph') - ->setAttribute('placeholder', 'invoices.form.invoice.placeholder.icdph'); + $form->addText('company_id', 'invoices.form.invoice.label.company_id') + ->setAttribute('placeholder', 'invoices.form.invoice.placeholder.company_id'); + $form->addText('company_tax_id', 'invoices.form.invoice.label.company_tax_id') + ->setAttribute('placeholder', 'invoices.form.invoice.placeholder.company_tax_id'); + $form->addText('company_vat_id', 'invoices.form.invoice.label.company_vat_id') + ->setAttribute('placeholder', 'invoices.form.invoice.placeholder.company_vat_id'); $contactEmail = $this->applicationConfig->get('contact_email'); - $form->addSelect('country_id', 'invoices.form.invoice.label.invoice_country_id', $this->countriesRepository->getDefaultCountryPair()) + $form->addSelect('country_id', 'invoices.form.invoice.label.country_id', $this->countriesRepository->getDefaultCountryPair()) ->setOption('id', 'invoice-country') ->setOption( 'description', diff --git a/src/lang/invoices.cs_CZ.neon b/src/lang/invoices.cs_CZ.neon index 1a384f8..9f71b32 100644 --- a/src/lang/invoices.cs_CZ.neon +++ b/src/lang/invoices.cs_CZ.neon @@ -7,7 +7,9 @@ frontend: not_available_anymore: Faktura již nedostupná generate: Vygeneruj system_error: Systémová chyba! Prosím kontaktujte technickou podporu! + invoice: Faktura download: Stáhni fakturu + edit: Uprav fakturu invoice_details: Fakturační údaje invoice_details: @@ -78,6 +80,13 @@ admin: invoices: Faktury generate: Vygeneruj scheduled: "Generování faktur bylo naplánováno, chvíli počkejte." + edit: + title: Úprava faktury + edit_invoice: Upravit adresu odběratele + current_invoice_address: Použít aktuální fakturační adresu + edit_items: Upravit položky + back_to_user: Zpět na uživatele + success: Faktura byla úspěšně změněna. component: payment_success_invoice_widget: @@ -97,10 +106,10 @@ form: number: Číslo city: Město zip: PSČ - ico: IČO - dic: DIČ - icdph: IČDPH - invoice_country_id: Země + country_id: Země + company_id: IČO + company_tax_id: DIČ + company_vat_id: IČDPH send: Uložit save: Uložit údaje placeholder: @@ -109,18 +118,19 @@ form: number: napište číslo domu city: napište město zip: napište PSČ - ico: například 23590235 - dic: například 2359023536 - icdph: například CZ2359023536 + company_id: například 23590235 + company_tax_id: například 2359023536 + company_vat_id: například CZ2359023536 required: company_name: Název firmy musí být vyplněn address: Adresa firmy musí být vyplněna number: Číslo domu musí být vyplněno city: Město musí být vyplněno zip: PSČ musí být vyplněno - ico: IČO musí být vyplněno - dic: DIČ musí být vyplněno - icdph: IČDPH musí být vyplněno + country_id: Země musí být vyplněna + company_id: IČO musí být vyplněno + company_tax_id: DIČ musí být vyplněno + company_vat_id: IČDPH musí být vyplněno options: foreign_country: "Pro informace o doručení do zahraničí nás prosím kontaktujte na %contactEmail%" diff --git a/src/lang/invoices.en_US.neon b/src/lang/invoices.en_US.neon index 7f90cb5..c5ab819 100644 --- a/src/lang/invoices.en_US.neon +++ b/src/lang/invoices.en_US.neon @@ -7,7 +7,9 @@ frontend: not_available_anymore: Invoice not available anymore generate: Generate system_error: System failure! Please contact tech support! + invoice: invoice download: Download invoice + edit: Edit invoice invoice_details: Invoice details invoice_details: @@ -78,6 +80,14 @@ admin: invoices: Invoices generate: Generate scheduled: "Batch generation was scheduled, please wait." + edit: + title: Edit invoice + edit_invoice: Edit buyer address + current_invoice_address: Use current invoice address + edit_items: Edit items + back_to_user: Back to user detail + success: Invoice was successfuly changed. + component: payment_success_invoice_widget: require_invoice: I need an invoice @@ -96,10 +106,10 @@ form: number: Number city: City zip: ZIP - ico: Businness ID - dic: Tax ID - icdph: VAT number - invoice_country_id: Country + country_id: Country + company_id: Businness ID + company_tax_id: Tax ID + company_vat_id: VAT number send: Save save: Save placeholder: @@ -108,18 +118,19 @@ form: number: house number city: fill your city zip: fill your zip - ico: e.g. 23590235 - dic: e.g. 2359023574 - icdph: e.g. SK2359023574 + company_id: e.g. 23590235 + company_tax_id: e.g. 2359023574 + company_vat_id: e.g. SK2359023574 required: company_name: Company name is required address: Company address is required number: House number is required city: City is required zip: ZIP is required - ico: Business ID is required - dic: Tax ID is required - icdph: VAT number is required + country_id: Country is required + company_id: Business ID is required + company_tax_id: Tax ID is required + company_vat_id: VAT number is required options: foreign_country: "For delivery to foreign countries please contact us through %contactEmail%" diff --git a/src/lang/invoices.sk_SK.neon b/src/lang/invoices.sk_SK.neon index daadfa4..436646c 100644 --- a/src/lang/invoices.sk_SK.neon +++ b/src/lang/invoices.sk_SK.neon @@ -7,7 +7,9 @@ frontend: not_available_anymore: Faktúra už nedostupná generate: Vygeneruj system_error: Systémová chyba! Prosím kontaktujte technickú podporu! + invoice: Faktúra download: Stiahni faktúru + edit: Uprav faktúru invoice_details: Fakturačné údaje invoice_details: @@ -78,6 +80,13 @@ admin: invoices: Faktúry generate: Vygeneruj scheduled: "Generovanie faktúr bolo naplánované, chvíľu počkajte." + edit: + title: Úprava faktúry + edit_invoice: Upraviť adresu odoberateľa + current_invoice_address: Použiť aktuálnu fakturačnú adresu + edit_items: Upraviť položky + back_to_user: Späť na používateľa + success: Faktúra bola úspešne zmenená. component: payment_success_invoice_widget: @@ -97,10 +106,10 @@ form: number: Číslo city: Mesto zip: PSČ - ico: IČO - dic: DIČ - icdph: IČDPH - invoice_country_id: Krajina + country_id: Krajina + company_id: IČO + company_tax_id: DIČ + company_vat_id: IČDPH send: Uložiť save: Uložiť údaje placeholder: @@ -109,20 +118,24 @@ form: number: napíšte číslo domu city: napíšte mesto zip: napíšte PSČ - ico: napríklad 25412547 - dic: napríklad 2541254765 - icdph: napríklad SK2541254765 + company_id: napríklad 25412547 + company_tax_id: napríklad 2541254765 + company_vat_id: napríklad SK2541254765 required: company_name: Názov firmy musí byť vyplnený address: Adresa firmy musí byť vyplnená number: Číslo domu musí byť vyplnené city: Mesto musí byť vyplnené zip: PSČ musí byť vyplnené - ico: IČO musí byť vyplnené - dic: DIČ musí byť vyplnené - icdph: IČDPH musí byť vyplnené + country_id: Krajina musí byť vyplnená + company_id: IČO musí byť vyplnené + company_tax_id: DIČ musí byť vyplnené + company_vat_id: IČDPH musí byť vyplnené options: foreign_country: "Pre informácie o doručení do zahraničia nás, prosím, kontaktujte na %contactEmail%" + change_invoice_items: + item: Položka %i% + placeholder: Názov položky invoice_template: title: Faktúra diff --git a/src/presenters/InvoicesAdminPresenter.php b/src/presenters/InvoicesAdminPresenter.php index 3f75c9f..09ae92c 100644 --- a/src/presenters/InvoicesAdminPresenter.php +++ b/src/presenters/InvoicesAdminPresenter.php @@ -4,12 +4,15 @@ use Crm\AdminModule\Presenters\AdminPresenter; use Crm\ApplicationModule\Hermes\HermesMessage; +use Crm\InvoicesModule\Forms\ChangeInvoiceFormFactory; +use Crm\InvoicesModule\Forms\ChangeInvoiceItemsFormFactory; use Crm\InvoicesModule\InvoiceGenerator; use Crm\InvoicesModule\Repository\InvoiceNumbersRepository; use Crm\InvoicesModule\Repository\InvoicesRepository; use Crm\InvoicesModule\Sandbox\InvoiceSandbox; use Crm\InvoicesModule\Sandbox\InvoiceZipGenerator; use Crm\PaymentsModule\Repository\PaymentsRepository; +use Crm\UsersModule\Repository\AddressesRepository; use Nette\Application\BadRequestException; use Nette\Application\Responses\TextResponse; use Nette\Application\UI\Form; @@ -40,6 +43,15 @@ class InvoicesAdminPresenter extends AdminPresenter /** @var Emitter @inject */ public $hermesEmitter; + /** @var ChangeInvoiceFormFactory @inject */ + public $changeInvoiceFormFactory; + + /** @var ChangeInvoiceItemsFormFactory @inject */ + public $changeInvoiceItemsFormFactory; + + /** @var AddressesRepository @inject */ + public $addressesRepository; + public function actionDownloadInvoice($id) { $payment = $this->paymentsRepository->find($id); @@ -154,4 +166,103 @@ public function handleDelete($filePath) } $this->redirect('default'); } + + public function renderEdit($id) + { + $invoice = $this->invoiceRepository->find($id); + if (!$invoice) { + throw new BadRequestException('Invalid invoice ID provided: ' . $this->getParameter('id')); + } + + $payment = $invoice->related('payments')->fetch(); + if (!$payment) { + throw new BadRequestException("Invoice {$this->getParameter('id')} is not related to any payment"); + } + + $pdf = $this->invoiceGenerator->renderInvoicePDF($payment->user, $payment); + + $this->template->pdf = $pdf; + $this->template->paymentId = $payment->id; + $this->template->user = $payment->user; + $this->template->invoice = $invoice; + } + + public function createComponentChangeInvoiceForm() + { + $id = $this->getParameter('id'); + $form = $this->changeInvoiceFormFactory->create($id); + + $invoice = $this->invoiceRepository->find($id); + if ($invoice) { + $defaults = [ + 'buyer_name' => $invoice->buyer_name, + 'buyer_address' => $invoice->buyer_address, + 'buyer_city' => $invoice->buyer_city, + 'buyer_zip' => $invoice->buyer_zip, + 'country_id' => $invoice->buyer_country_id, + 'company_id' => $invoice->buyer_id, + 'company_tax_id' => $invoice->buyer_tax_id, + 'company_vat_id' => $invoice->buyer_vat_id + ]; + $form->setDefaults($defaults); + } + + $this->changeInvoiceFormFactory->onSuccess = function () { + $this->flashMessage($this->translator->translate('invoices.admin.edit.success')); + }; + + $form->onError[] = function ($form) { + $this->flashMessage(implode('', $form->getErrors()), 'error'); + }; + return $form; + } + + public function createComponentCurrentInvoiceDetailsForm() + { + $id = $this->getParameter('id'); + $form = $this->changeInvoiceFormFactory->create($id); + + $invoice = $this->invoiceRepository->find($id); + if ($invoice) { + $payment = $invoice->related('payments')->fetch(); + if ($payment) { + $address = $this->addressesRepository->address($payment->user, 'invoice'); + if ($address) { + $defaults = [ + 'buyer_name' => $address->company_name, + 'buyer_address' => $address->address . ' ' . $address->number, + 'buyer_city' => $address->city, + 'buyer_zip' => $address->zip, + 'country_id' => $address->country_id, + 'company_id' => $address->company_id, + 'company_tax_id' => $address->company_tax_id, + 'company_vat_id' => $address->company_vat_id + ]; + $form->setDefaults($defaults); + } + } + } + + $this->changeInvoiceFormFactory->onSuccess = function () { + $this->flashMessage($this->translator->translate('invoices.admin.edit.success')); + }; + $form->onError[] = function ($form) { + $this->flashMessage(implode('', $form->getErrors()), 'error'); + }; + return $form; + } + + public function createComponentInvoiceItemsForm() + { + $id = $this->getParameter('id'); + $form = $this->changeInvoiceItemsFormFactory->create($id); + + $this->changeInvoiceItemsFormFactory->onSuccess = function () { + $this->flashMessage($this->translator->translate('invoices.admin.edit.success')); + }; + $form->onError[] = function ($form) { + $this->flashMessage(implode('', $form->getErrors()), 'error'); + }; + return $form; + } } diff --git a/src/templates/InvoicesAdmin/edit.latte b/src/templates/InvoicesAdmin/edit.latte new file mode 100644 index 0000000..2e7daf6 --- /dev/null +++ b/src/templates/InvoicesAdmin/edit.latte @@ -0,0 +1,98 @@ +{block #content} + + +
+
+ {_invoices.admin.edit.back_to_user} + +
+
+ +
+ +
+ + + + + + +