From 22b7d74fe05347d8be79c41a794de5d271369b26 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Fri, 29 Oct 2021 14:49:55 +0200 Subject: [PATCH] bug and media fixes --- Controller/ApiController.php | 175 ++++++--- Models/Report.php | 57 +-- Models/Template.php | 116 +----- tests/Bootstrap.php | 2 +- tests/Controller/ApiControllerTest.php | 440 +++++++++++++++++++++++ tests/Models/ReportMapperTest.php | 10 +- tests/Models/ReportTest.php | 16 +- tests/Models/TemplateMapperTest.php | 17 +- tests/Models/TemplateTest.php | 63 +++- tests/depreciation/depreciation.cfg.json | 44 +++ tests/depreciation/depreciation.lang.php | 27 ++ tests/depreciation/logo.png | Bin 0 -> 90210 bytes tests/depreciation/reportData.csv | 1 + tests/depreciation/styles.css | 163 +++++++++ tests/depreciation/test.js | 0 tests/depreciation/test.json | 0 tests/depreciation/test.sqlite | 0 tests/depreciation/view.csv.php | 48 +++ tests/depreciation/view.doc.php | 190 ++++++++++ tests/depreciation/view.json.php | 3 + tests/depreciation/view.pdf.php | 90 +++++ tests/depreciation/view.ppt.php | 333 +++++++++++++++++ tests/depreciation/view.tpl.php | 58 +++ tests/depreciation/view.xls.php | 56 +++ 24 files changed, 1667 insertions(+), 242 deletions(-) create mode 100644 tests/Controller/ApiControllerTest.php create mode 100644 tests/depreciation/depreciation.cfg.json create mode 100644 tests/depreciation/depreciation.lang.php create mode 100644 tests/depreciation/logo.png create mode 100644 tests/depreciation/reportData.csv create mode 100644 tests/depreciation/styles.css create mode 100644 tests/depreciation/test.js create mode 100644 tests/depreciation/test.json create mode 100644 tests/depreciation/test.sqlite create mode 100644 tests/depreciation/view.csv.php create mode 100644 tests/depreciation/view.doc.php create mode 100644 tests/depreciation/view.json.php create mode 100644 tests/depreciation/view.pdf.php create mode 100644 tests/depreciation/view.ppt.php create mode 100644 tests/depreciation/view.tpl.php create mode 100644 tests/depreciation/view.xls.php diff --git a/Controller/ApiController.php b/Controller/ApiController.php index d559c11..bef1a66 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -38,6 +38,7 @@ use phpOMS\Message\Http\RequestStatusCode; use phpOMS\Message\NotificationLevel; use phpOMS\Message\RequestAbstract; use phpOMS\Message\ResponseAbstract; +use phpOMS\Model\Message\FormValidation; use phpOMS\System\MimeType; use phpOMS\Utils\Parser\Markdown\Markdown; use phpOMS\Utils\StringUtils; @@ -68,29 +69,29 @@ final class ApiController extends Controller */ public function apiHelperExport(HttpRequest $request, HttpResponse $response, $data = null) : void { + if (!empty($val = $this->validateExport($request))) { + $response->set('export', new FormValidation($val)); + $response->header->status = RequestStatusCode::R_400; + + return; + } + /** @var Template $template */ $template = TemplateMapper::get((int) $request->getData('id')); $accountId = $request->header->account; + $isExport = \in_array($request->getData('type'), ['xlsx', 'pdf', 'docx', 'pptx', 'csv', 'json']); + // is allowed to read - if (!$this->app->accountManager->get($accountId)->hasPermission( - PermissionType::READ, $this->app->orgId, null, self::NAME, PermissionState::REPORT, $template->getId()) + if (!$this->app->accountManager->get($accountId)->hasPermission(PermissionType::READ, $this->app->orgId, null, self::NAME, PermissionState::REPORT, $template->getId()) + || ($isExport && !$this->app->accountManager->get($accountId)->hasPermission(PermissionType::READ, $this->app->orgId, $this->app->appName, self::NAME, PermissionState::EXPORT)) ) { $response->header->status = RequestStatusCode::R_403; return; } - if (\in_array($request->getData('type'), ['xlsx', 'pdf', 'docx', 'pptx', 'csv'])) { - // is allowed to export - if (!$this->app->accountManager->get($accountId)->hasPermission( - PermissionType::READ, $this->app->orgId, $this->app->appName, self::NAME, PermissionState::EXPORT - )) { - $response->header->status = RequestStatusCode::R_403; - - return; - } - + if ($isExport) { Autoloader::addPath(__DIR__ . '/../../../Resources/'); $response->header->setDownloadable($template->name, (string) $request->getData('type')); } @@ -102,6 +103,25 @@ final class ApiController extends Controller $response->set('export', $view); } + /** + * Validate export request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateExport(RequestAbstract $request) : array + { + $val = []; + if (($val['id'] = empty($request->getData('id')))) { + return $val; + } + + return []; + } + /** * Set header for report/template * @@ -127,7 +147,7 @@ final class ApiController extends Controller . '"' , true); $response->header->set('Content-Type', MimeType::M_PDF, true); - $view->setTemplate('/' . \substr($view->getData('tcoll')['pdf']->getPath(), 0, -8), 'pdf.php'); + $view->setTemplate('/' . \substr($view->getData('tcoll')['pdf']?->getPath(), 0, -8), 'pdf.php'); break; case 'csv': $response->header->set( @@ -137,7 +157,7 @@ final class ApiController extends Controller . '"' , true); $response->header->set('Content-Type', MimeType::M_CONF, true); - $view->setTemplate('/' . \substr($view->getData('tcoll')['csv']->getPath(), 0, -8), 'csv.php'); + $view->setTemplate('/' . \substr($view->getData('tcoll')['csv']?->getPath(), 0, -8), 'csv.php'); break; case 'xls': case 'xlsx': @@ -148,7 +168,7 @@ final class ApiController extends Controller . '"' , true); $response->header->set('Content-Type', MimeType::M_XLSX, true); - $view->setTemplate('/' . \substr($view->getData('tcoll')['excel']->getPath(), 0, -8), 'xls.php'); + $view->setTemplate('/' . \substr($view->getData('tcoll')['excel']?->getPath(), 0, -8), 'xls.php'); break; case 'doc': case 'docx': @@ -159,7 +179,7 @@ final class ApiController extends Controller . '"' , true); $response->header->set('Content-Type', MimeType::M_XLSX, true); - $view->setTemplate('/' . \substr($view->getData('tcoll')['word']->getPath(), 0, -8), 'doc.php'); + $view->setTemplate('/' . \substr($view->getData('tcoll')['word']?->getPath(), 0, -8), 'doc.php'); break; case 'ppt': case 'pptx': @@ -170,15 +190,15 @@ final class ApiController extends Controller . '"' , true); $response->header->set('Content-Type', MimeType::M_XLSX, true); - $view->setTemplate('/' . \substr($view->getData('tcoll')['powerpoint']->getPath(), 0, -8), 'ppt.php'); + $view->setTemplate('/' . \substr($view->getData('tcoll')['powerpoint']?->getPath(), 0, -8), 'ppt.php'); break; case 'json': $response->header->set('Content-Type', MimeType::M_JSON, true); - $view->setTemplate('/' . \substr($view->getData('tcoll')['json']->getPath(), 0, -9), 'json.php'); + $view->setTemplate('/' . \substr($view->getData('tcoll')['json']?->getPath(), 0, -9), 'json.php'); break; default: $response->header->set('Content-Type', 'text/html; charset=utf-8'); - $view->setTemplate('/' . \substr($view->getData('tcoll')['template']->getPath(), 0, -8)); + $view->setTemplate('/' . \substr($view->getData('tcoll')['template']?->getPath(), 0, -8)); } } @@ -199,7 +219,7 @@ final class ApiController extends Controller { /** @var array $tcoll */ $tcoll = []; - $files = $template->getSource()->getSources(); + $files = $template->source->getSources(); /** @var \Modules\Media\Models\Media $tMedia */ foreach ($files as $tMedia) { @@ -264,7 +284,7 @@ final class ApiController extends Controller } $view = new View($this->app->l11nManager, $request, $response); - if (!$template->isStandalone()) { + if (!$template->isStandalone) { /** @var Report[] $report */ $report = ReportMapper::getNewest(1, (new Builder($this->app->dbPool->get()))->where('helper_report.helper_report_template', '=', $template->getId()) @@ -275,7 +295,7 @@ final class ApiController extends Controller $report = $report === false ? new NullReport() : $report; if (!($report instanceof NullReport)) { - $files = $report->getSource()->getSources(); + $files = $report->source->getSources(); foreach ($files as $media) { $rcoll[$media->name . '.' . $media->extension] = $media; @@ -313,17 +333,30 @@ final class ApiController extends Controller $uploadedFiles = $request->getFiles() ?? []; $files = []; - if (!empty($uploadedFiles)) { - $uploaded = $this->app->moduleManager->get('Media')->uploadFiles( - [$request->getData('name') ?? ''], - $uploadedFiles, - $request->header->account, - __DIR__ . '/../../../Modules/Media/Files' - ); + if (!empty($val = $this->validateTemplateCreate($request))) { + $response->set('template_create', new FormValidation($val)); + $response->header->status = RequestStatusCode::R_400; - foreach ($uploaded as $upload) { - $files[] = new NullMedia($upload->getId()); - } + return; + } + + // is allowed to create + if (!$this->app->accountManager->get($request->header->account)->hasPermission(PermissionType::CREATE, $this->app->orgId, null, self::NAME, PermissionState::TEMPLATE)) { + $response->header->status = RequestStatusCode::R_403; + + return; + } + + $uploaded = $this->app->moduleManager->get('Media')->uploadFiles( + $request->getDataList('names') ?? [], + $request->getDataList('filenames') ?? [], + $uploadedFiles, + $request->header->account, + __DIR__ . '/../../../Modules/Media/Files' + ); + + foreach ($uploaded as $upload) { + $files[] = new NullMedia($upload->getId()); } foreach ($dbFiles as $db) { @@ -338,9 +371,6 @@ final class ApiController extends Controller $request->header->account ); - $collection->setPath('/Modules/Media/Files/Modules/Helper/' . ((string) ($request->getData('name') ?? ''))); - $collection->setVirtualPath('/Modules/Helper'); - if ($collection instanceof NullCollection) { $response->header->status = RequestStatusCode::R_403; $this->fillJsonResponse($request, $response, NotificationLevel::ERROR, 'Template', 'Couldn\'t create collection for template', null); @@ -348,6 +378,9 @@ final class ApiController extends Controller return; } + $collection->setPath('/Modules/Media/Files/Modules/Helper/' . ((string) ($request->getData('name') ?? ''))); + $collection->setVirtualPath('/Modules/Helper'); + CollectionMapper::create($collection); $template = $this->createTemplateFromRequest($request, $collection->getId()); @@ -372,6 +405,27 @@ final class ApiController extends Controller $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Template', 'Template successfully created', $template); } + /** + * Validate template create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateTemplateCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['name'] = empty($request->getData('name'))) + || ($val['files'] = empty($request->getFiles() ?? [])) + ) { + return $val; + } + + return []; + } + /** * Method to create template from request. * @@ -391,14 +445,14 @@ final class ApiController extends Controller $helperTemplate->descriptionRaw = (string) ($request->getData('description') ?? ''); if ($collectionId > 0) { - $helperTemplate->setSource(new NullCollection($collectionId)); + $helperTemplate->source = new NullCollection($collectionId); } - $helperTemplate->setStandalone((bool) ($request->getData('standalone') ?? false)); + $helperTemplate->isStandalone = (bool) ($request->getData('standalone') ?? false); $helperTemplate->setExpected(!empty($expected) ? \json_decode($expected, true) : []); $helperTemplate->createdBy = new NullAccount($request->header->account); $helperTemplate->setDatatype((int) ($request->getData('datatype') ?? TemplateDataType::OTHER)); - $helperTemplate->setVirtualPath((string) ($request->getData('virtualpath') ?? '/')); + $helperTemplate->virtualPath = (string) ($request->getData('virtualpath') ?? '/'); if (!empty($tags = $request->getDataJson('tags'))) { foreach ($tags as $tag) { @@ -435,8 +489,23 @@ final class ApiController extends Controller */ public function apiReportCreate(RequestAbstract $request, ResponseAbstract $response, $data = null) : void { + if (!empty($val = $this->validateReportCreate($request))) { + $response->set('report_create', new FormValidation($val)); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + // is allowed to create + if (!$this->app->accountManager->get($request->header->account)->hasPermission(PermissionType::CREATE, $this->app->orgId, null, self::NAME, PermissionState::REPORT)) { + $response->header->status = RequestStatusCode::R_403; + + return; + } + $files = $this->app->moduleManager->get('Media')->uploadFiles( - [$request->getData('name') ?? ''], + $request->getDataList('names') ?? [], + $request->getDataList('filenames') ?? [], $request->getFiles(), $request->header->account, __DIR__ . '/../../../Modules/Media/Files' @@ -483,6 +552,26 @@ final class ApiController extends Controller $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Report', 'Report successfully created', $report); } + /** + * Validate template create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateReportCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['template'] = empty($request->getData('template'))) + ) { + return $val; + } + + return []; + } + /** * Method to create report from request. * @@ -496,10 +585,10 @@ final class ApiController extends Controller */ private function createReportFromRequest(RequestAbstract $request, ResponseAbstract $response, int $collectionId) : Report { - $helperReport = new Report(); - $helperReport->title = (string) ($request->getData('name')); - $helperReport->setSource(new NullCollection($collectionId)); - $helperReport->setTemplate(new NullTemplate((int) $request->getData('template'))); + $helperReport = new Report(); + $helperReport->title = (string) ($request->getData('name')); + $helperReport->source = new NullCollection($collectionId); + $helperReport->template = new NullTemplate((int) $request->getData('template')); $helperReport->createdBy = new NullAccount($request->header->account); return $helperReport; diff --git a/Models/Report.php b/Models/Report.php index 0d98ef1..44821d2 100755 --- a/Models/Report.php +++ b/Models/Report.php @@ -16,7 +16,6 @@ namespace Modules\Helper\Models; use Modules\Admin\Models\Account; use Modules\Admin\Models\NullAccount; -use Modules\Helper\Admin\Install\Media; use Modules\Media\Models\Collection; use Modules\Media\Models\NullCollection; @@ -92,7 +91,7 @@ class Report implements \JsonSerializable * @var Template * @since 1.0.0 */ - private Template $template; + public Template $template; /** * Report source. @@ -100,7 +99,7 @@ class Report implements \JsonSerializable * @var Collection * @since 1.0.0 */ - private Collection $source; + public Collection $source; /** * Constructor. @@ -153,58 +152,6 @@ class Report implements \JsonSerializable $this->status = $status; } - /** - * Get template this report belongs to - * - * @return Template - * - * @since 1.0.0 - */ - public function getTemplate() : Template - { - return $this->template; - } - - /** - * Set template this report belongs to - * - * @param Template $template Report template - * - * @return void - * - * @since 1.0.0 - */ - public function setTemplate(Template $template) : void - { - $this->template = $template; - } - - /** - * Set source media for the report - * - * @param Collection $source Report source - * - * @return void - * - * @since 1.0.0 - */ - public function setSource(Collection $source) : void - { - $this->source = $source; - } - - /** - * Get source media for the report - * - * @return Collection - * - * @since 1.0.0 - */ - public function getSource() : Collection - { - return $this->source; - } - /** * {@inheritdoc} */ diff --git a/Models/Template.php b/Models/Template.php index acbbc29..88f47de 100755 --- a/Models/Template.php +++ b/Models/Template.php @@ -46,7 +46,7 @@ class Template implements \JsonSerializable * @var Unit * @since 1.0.0 */ - private Unit $unit; + public Unit $unit; /** * Template status. @@ -70,7 +70,7 @@ class Template implements \JsonSerializable * @var bool * @since 1.0.0 */ - private bool $isStandalone = false; + public bool $isStandalone = false; /** * Template name. @@ -118,7 +118,7 @@ class Template implements \JsonSerializable * @var Collection * @since 1.0.0 */ - private Collection $source; + public Collection $source; /** * Expected files. @@ -149,8 +149,10 @@ class Template implements \JsonSerializable * * @var string * @since 1.0.0 + * + * @todo maybe never used, check */ - private string $virtualPath = '/'; + public string $virtualPath = '/'; /** * Constructor @@ -177,34 +179,6 @@ class Template implements \JsonSerializable return $this->id; } - /** - * Get unit this template belogns to - * - * @return Unit - * - * @since 1.0.0 - */ - public function getUnit() : Unit - { - return $this->unit; - } - - /** - * Set unit this model belongs to - * - * Set the unit - * - * @param Unit $unit Unit - * - * @return void - * - * @since 1.0.0 - */ - public function setUnit(Unit $unit) : void - { - $this->unit = $unit; - } - /** * Get newest report for template. * @@ -221,58 +195,6 @@ class Template implements \JsonSerializable return new NullReport(); } - /** - * Get the path - * - * @return string - * - * @since 1.0.0 - */ - public function getVirtualPath() : string - { - return $this->virtualPath; - } - - /** - * Set the path if file - * - * @param string $path Path to file - * - * @return mixed - * - * @since 1.0.0 - */ - public function setVirtualPath(string $path) - { - $this->virtualPath = $path; - } - - /** - * Set source media - * - * @param Collection $source Source - * - * @return void - * - * @since 1.0.0 - */ - public function setSource(Collection $source) : void - { - $this->source = $source; - } - - /** - * Get source media - * - * @return Collection - * - * @since 1.0.0 - */ - public function getSource() : Collection - { - return $this->source; - } - /** * Get expected files from report * @@ -365,32 +287,6 @@ class Template implements \JsonSerializable return $this->datatype; } - /** - * Set if the template needs report data - * - * @param bool $isStandalone Is template standalone - * - * @return void - * - * @since 1.0.0 - */ - public function setStandalone(bool $isStandalone) : void - { - $this->isStandalone = $isStandalone; - } - - /** - * Does the template need report data? - * - * @return bool - * - * @since 1.0.0 - */ - public function isStandalone() : bool - { - return $this->isStandalone; - } - /** * Get tags * diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 051ac7e..f5fc99c 100755 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -392,4 +392,4 @@ function phpServe() : void }); } -phpServe(); +\phpServe(); diff --git a/tests/Controller/ApiControllerTest.php b/tests/Controller/ApiControllerTest.php new file mode 100644 index 0000000..b6489ea --- /dev/null +++ b/tests/Controller/ApiControllerTest.php @@ -0,0 +1,440 @@ +app = new class() extends ApplicationAbstract + { + protected string $appName = 'Api'; + }; + + $this->app->dbPool = $GLOBALS['dbpool']; + $this->app->orgId = 1; + $this->app->accountManager = new AccountManager($GLOBALS['session']); + $this->app->appSettings = new CoreSettings(); + $this->app->moduleManager = new ModuleManager($this->app, __DIR__ . '/../../../../Modules/'); + $this->app->dispatcher = new Dispatcher($this->app); + $this->app->eventManager = new EventManager($this->app->dispatcher); + $this->app->eventManager->importFromFile(__DIR__ . '/../../../../Web/Api/Hooks.php'); + $this->app->sessionManager = new HttpSession(36000); + + $account = new Account(); + TestUtils::setMember($account, 'id', 1); + + $permission = new AccountPermission(); + $permission->setUnit(1); + $permission->setApp('api'); + $permission->setPermission( + PermissionType::READ + | PermissionType::CREATE + | PermissionType::MODIFY + | PermissionType::DELETE + | PermissionType::PERMISSION + ); + + $account->addPermission($permission); + + $this->app->accountManager->add($account); + $this->app->router = new WebRouter(); + + $this->module = $this->app->moduleManager->get('Helper'); + + TestUtils::setMember($this->module, 'app', $this->app); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testStandaloneTemplateCreate() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('name', \ucfirst('depreciation')); + $request->setData('standalone', true); + $request->setData('tags', '[{"title": "TestTitle", "color": "#f0f", "language": "en"}, {"id": 1}]'); + + $files = []; + + if (!\is_dir(__DIR__ . '/temp')) { + \mkdir(__DIR__ . '/temp'); + } + + $helperFiles = \scandir(__DIR__ . '/../depreciation'); + foreach ($helperFiles as $filePath) { + if (!\is_file(__DIR__ . '/../depreciation/' . $filePath) + || $filePath === '..' || $filePath === '.' + ) { + continue; + } + + \copy(__DIR__ . '/../depreciation/' . $filePath, __DIR__ . '/temp/' . $filePath); + + $files[] = [ + 'error' => \UPLOAD_ERR_OK, + 'type' => \substr($filePath, \strrpos($filePath, '.') + 1), + 'name' => $filePath, + 'tmp_name' => __DIR__ . '/temp/' . $filePath, + 'size' => \filesize(__DIR__ . '/temp/' . $filePath), + ]; + } + + TestUtils::setMember($request, 'files', $files); + + $this->module->apiTemplateCreate($request, $response); + self::assertGreaterThan(0, self::$depreciationHelper = $response->get('')['response']->getId()); + + \rmdir(__DIR__ . '/temp'); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testTemplateCreate() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('name', \ucfirst('depreciation')); + $request->setData('standalone', false); + $request->setData('tags', '[{"title": "TestTitle", "color": "#f0f", "language": "en"}, {"id": 1}]'); + + $files = []; + + if (!\is_dir(__DIR__ . '/temp')) { + \mkdir(__DIR__ . '/temp'); + } + + $helperFiles = \scandir(__DIR__ . '/../depreciation'); + foreach ($helperFiles as $filePath) { + if (!\is_file(__DIR__ . '/../depreciation/' . $filePath) + || $filePath === '..' || $filePath === '.' + ) { + continue; + } + + \copy(__DIR__ . '/../depreciation/' . $filePath, __DIR__ . '/temp/' . $filePath); + + $files[] = [ + 'error' => \UPLOAD_ERR_OK, + 'type' => \substr($filePath, \strrpos($filePath, '.') + 1), + 'name' => $filePath, + 'tmp_name' => __DIR__ . '/temp/' . $filePath, + 'size' => \filesize(__DIR__ . '/temp/' . $filePath), + ]; + } + + TestUtils::setMember($request, 'files', $files); + + $this->module->apiTemplateCreate($request, $response); + self::assertGreaterThan(0, self::$depreciationHelper2 = $response->get('')['response']->getId()); + + \rmdir(__DIR__ . '/temp'); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testExportPdf() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('id', self::$depreciationHelper); + $request->setData('type', 'pdf'); + + $this->module->apiHelperExport($request, $response); + self::assertTrue(\stripos($response->header->get('Content-disposition')[0], 'pdf') !== false); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testExportXlsx() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('id', self::$depreciationHelper); + $request->setData('type', 'xlsx'); + + $this->module->apiHelperExport($request, $response); + self::assertTrue(\stripos($response->header->get('Content-disposition')[0], 'xlsx') !== false); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testExportDocx() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('id', self::$depreciationHelper); + $request->setData('type', 'docx'); + + $this->module->apiHelperExport($request, $response); + self::assertTrue(\stripos($response->header->get('Content-disposition')[0], 'docx') !== false); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testExportPptx() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('id', self::$depreciationHelper); + $request->setData('type', 'pptx'); + + $this->module->apiHelperExport($request, $response); + self::assertTrue(\stripos($response->header->get('Content-disposition')[0], 'pptx') !== false); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testExportCsv() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('id', self::$depreciationHelper); + $request->setData('type', 'csv'); + + $this->module->apiHelperExport($request, $response); + self::assertTrue(\stripos($response->header->get('Content-disposition')[0], 'csv') !== false); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testExportJson() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('id', self::$depreciationHelper); + $request->setData('type', 'json'); + + $this->module->apiHelperExport($request, $response); + self::assertTrue(\stripos($response->header->get('Content-disposition')[0], 'json') !== false); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testExportInvalidPermission() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 99999; + $request->setData('id', self::$depreciationHelper); + $request->setData('type', 'csv'); + + $this->module->apiHelperExport($request, $response); + self::assertEquals(RequestStatusCode::R_403, $response->header->status); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testExportOtherType() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('id', self::$depreciationHelper); + $request->setData('type', 'invalid'); + + $this->module->apiHelperExport($request, $response); + self::assertEquals(RequestStatusCode::R_200, $response->header->status); // is html "export"/render + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testExportInvalidData() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('invalid', '1'); + + $this->module->apiHelperExport($request, $response); + self::assertEquals(RequestStatusCode::R_400, $response->header->status); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testApiTemplateCreateInvalidData() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('invalid', '1'); + + $this->module->apiTemplateCreate($request, $response); + self::assertEquals(RequestStatusCode::R_400, $response->header->status); + } + + /** + * @depends testTemplateCreate + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testReportCreate() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('name', \ucfirst('depreciation-report')); + $request->setData('template', self::$depreciationHelper2); + + if (!\is_file(__DIR__ . '/reportData_tmp.csv')) { + \copy(__DIR__ . '/../depreciation/reportData.csv', __DIR__ . '/reportData_tmp.csv'); + } + + TestUtils::setMember($request, 'files', [ + [ + 'name' => 'reportData.csv', + 'type' => 'csv', + 'error' => \UPLOAD_ERR_OK, + 'tmp_name' => __DIR__ . '/reportData_tmp.csv', + 'size' => \filesize(__DIR__ . '/reportData_tmp.csv'), + ], + ]); + + $this->module->apiReportCreate($request, $response); + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testReportCreateInvalidPermission() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 9999; + $request->setData('name', \ucfirst('depreciation-report')); + $request->setData('template', self::$depreciationHelper2); + + if (!\is_file(__DIR__ . '/reportData_tmp.csv')) { + \copy(__DIR__ . '/../depreciation/reportData.csv', __DIR__ . '/reportData_tmp.csv'); + } + + TestUtils::setMember($request, 'files', [ + [ + 'name' => 'reportData.csv', + 'type' => 'csv', + 'error' => \UPLOAD_ERR_OK, + 'tmp_name' => __DIR__ . '/reportData_tmp.csv', + 'size' => \filesize(__DIR__ . '/reportData_tmp.csv'), + ], + ]); + + $this->module->apiReportCreate($request, $response); + self::assertEquals(RequestStatusCode::R_403, $response->header->status); + + if (\is_file(__DIR__ . '/reportData_tmp.csv')) { + \unlink(__DIR__ . '/reportData_tmp.csv'); + } + } + + /** + * @covers Modules\Helper\Controller\ApiController + * @group module + */ + public function testApiReportCreateInvalidData() : void + { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('invalid', '1'); + + $this->module->apiReportCreate($request, $response); + self::assertEquals(RequestStatusCode::R_400, $response->header->status); + } +} diff --git a/tests/Models/ReportMapperTest.php b/tests/Models/ReportMapperTest.php index 0c3c8f1..1dd8dd4 100755 --- a/tests/Models/ReportMapperTest.php +++ b/tests/Models/ReportMapperTest.php @@ -39,7 +39,7 @@ final class ReportMapperTest extends \PHPUnit\Framework\TestCase $template->setStatus(HelperStatus::ACTIVE); $template->description = 'Description'; $template->setDatatype(TemplateDataType::OTHER); - $template->setStandalone(false); + $template->isStandalone = false; $template->setExpected(['source1.csv', 'source2.csv']); $collection = new Collection(); @@ -94,7 +94,7 @@ final class ReportMapperTest extends \PHPUnit\Framework\TestCase $collection->addSource($media); } - $template->setSource($collection); + $template->source = $collection; return $template; } @@ -112,7 +112,7 @@ final class ReportMapperTest extends \PHPUnit\Framework\TestCase $report->title = 'Title'; $report->setStatus(HelperStatus::ACTIVE); $report->description = 'Description'; - $report->setTemplate($this->createTemplate()); + $report->template = $this->createTemplate(); $collection = new Collection(); $collection->createdBy = new NullAccount(1); @@ -166,7 +166,7 @@ final class ReportMapperTest extends \PHPUnit\Framework\TestCase $collection->addSource($media); } - $report->setSource($collection); + $report->source = $collection; $id = ReportMapper::create($report); self::assertGreaterThan(0, $report->getId()); @@ -178,6 +178,6 @@ final class ReportMapperTest extends \PHPUnit\Framework\TestCase self::assertEquals($report->description, $reportR->description); self::assertEquals($report->title, $reportR->title); self::assertEquals($report->getStatus(), $reportR->getStatus()); - self::assertEquals($report->getTemplate()->name, $reportR->getTemplate()->name); + self::assertEquals($report->template->name, $reportR->template->name); } } diff --git a/tests/Models/ReportTest.php b/tests/Models/ReportTest.php index f3eb9cb..41435e0 100755 --- a/tests/Models/ReportTest.php +++ b/tests/Models/ReportTest.php @@ -51,8 +51,8 @@ final class ReportTest extends \PHPUnit\Framework\TestCase self::assertEquals(HelperStatus::INACTIVE, $this->report->getStatus()); self::assertEquals('', $this->report->description); self::assertEquals('', $this->report->descriptionRaw); - self::assertEquals(0, $this->report->getTemplate()->getId()); - self::assertEquals(0, $this->report->getSource()->getId()); + self::assertEquals(0, $this->report->template->getId()); + self::assertEquals(0, $this->report->source->getId()); } /** @@ -117,8 +117,8 @@ final class ReportTest extends \PHPUnit\Framework\TestCase */ public function testTemplateInputOutput() : void { - $this->report->setTemplate(new NullTemplate(11)); - self::assertEquals(11, $this->report->getTemplate()->getId()); + $this->report->template = new NullTemplate(11); + self::assertEquals(11, $this->report->template->getId()); } /** @@ -128,8 +128,8 @@ final class ReportTest extends \PHPUnit\Framework\TestCase */ public function testSourceInputOutput() : void { - $this->report->setSource(new NullCollection(4)); - self::assertEquals(4, $this->report->getSource()->getId()); + $this->report->source = new NullCollection(4); + self::assertEquals(4, $this->report->source->getId()); } /** @@ -139,7 +139,7 @@ final class ReportTest extends \PHPUnit\Framework\TestCase */ public function testToArray() : void { - $this->report->setTemplate(new NullTemplate(11)); + $this->report->template = new NullTemplate(11); $this->report->title = 'testTitle'; $this->report->description = 'testDescription'; $this->report->descriptionRaw = 'testDescriptionRaw'; @@ -169,7 +169,7 @@ final class ReportTest extends \PHPUnit\Framework\TestCase */ public function testJsonSerialize() : void { - $this->report->setTemplate(new NullTemplate(11)); + $this->report->template = new NullTemplate(11); $this->report->title = 'testTitle'; $this->report->description = 'testDescription'; $this->report->descriptionRaw = 'testDescriptionRaw'; diff --git a/tests/Models/TemplateMapperTest.php b/tests/Models/TemplateMapperTest.php index 6416d5a..b4f47b0 100755 --- a/tests/Models/TemplateMapperTest.php +++ b/tests/Models/TemplateMapperTest.php @@ -44,7 +44,7 @@ final class TemplateMapperTest extends \PHPUnit\Framework\TestCase $template->description = 'Description'; $template->descriptionRaw = 'DescriptionRaw'; $template->setDatatype(TemplateDataType::OTHER); - $template->setStandalone(false); + $template->isStandalone = false; $template->setExpected(['source1.csv', 'source2.csv']); $collection = new Collection(); @@ -99,7 +99,7 @@ final class TemplateMapperTest extends \PHPUnit\Framework\TestCase $collection->addSource($media); } - $template->setSource($collection); + $template->source = $collection; $id = TemplateMapper::create($template); self::assertGreaterThan(0, $template->getId()); @@ -112,7 +112,7 @@ final class TemplateMapperTest extends \PHPUnit\Framework\TestCase self::assertEquals($template->descriptionRaw, $templateR->descriptionRaw); self::assertEquals($template->name, $templateR->name); self::assertEquals($template->getStatus(), $templateR->getStatus()); - self::assertEquals($template->isStandalone(), $templateR->isStandalone()); + self::assertEquals($template->isStandalone, $templateR->isStandalone); self::assertEquals($template->getDatatype(), $templateR->getDatatype()); self::assertEquals($template->getExpected(), $templateR->getExpected()); } @@ -128,4 +128,15 @@ final class TemplateMapperTest extends \PHPUnit\Framework\TestCase self::assertCount(1, $newest); } + + /** + * @covers Modules\Helper\Models\TemplateMapper + * @group module + */ + public function testVirtualPath() : void + { + $virtualPath = TemplateMapper::getByVirtualPath('/'); + + self::assertGreaterThan(0, \count($virtualPath)); + } } diff --git a/tests/Models/TemplateTest.php b/tests/Models/TemplateTest.php index 0c36d83..6396e0f 100755 --- a/tests/Models/TemplateTest.php +++ b/tests/Models/TemplateTest.php @@ -21,6 +21,8 @@ use Modules\Helper\Models\Template; use Modules\Helper\Models\TemplateDataType; use Modules\Media\Models\NullCollection; use Modules\Organization\Models\NullUnit; +use Modules\Tag\Models\Tag; +use phpOMS\Utils\TestUtils; /** * @testdox Modules\tests\Helper\Models\TemplateTest: Template model @@ -47,7 +49,7 @@ final class TemplateTest extends \PHPUnit\Framework\TestCase public function testDefault() : void { self::assertEquals(0, $this->template->getId()); - self::assertEquals(0, $this->template->getUnit()->getId()); + self::assertEquals(0, $this->template->unit->getId()); self::assertEquals(0, $this->template->createdBy->getId()); self::assertEquals((new \DateTime('now'))->format('Y-m-d'), $this->template->createdAt->format('Y-m-d')); self::assertEquals('', $this->template->name); @@ -55,8 +57,8 @@ final class TemplateTest extends \PHPUnit\Framework\TestCase self::assertEquals('', $this->template->description); self::assertEquals('', $this->template->descriptionRaw); self::assertEquals([], $this->template->getExpected()); - self::assertEquals(0, $this->template->getSource()->getId()); - self::assertFalse($this->template->isStandalone()); + self::assertEquals(0, $this->template->source->getId()); + self::assertFalse($this->template->isStandalone); self::assertEquals(TemplateDataType::OTHER, $this->template->getDatatype()); self::assertInstanceOf(NullReport::class, $this->template->getNewestReport()); } @@ -68,8 +70,8 @@ final class TemplateTest extends \PHPUnit\Framework\TestCase */ public function testUnitInputOutput() : void { - $this->template->setUnit(new NullUnit(1)); - self::assertEquals(1, $this->template->getUnit()->getId()); + $this->template->unit = new NullUnit(1); + self::assertEquals(1, $this->template->unit->getId()); } /** @@ -112,8 +114,8 @@ final class TemplateTest extends \PHPUnit\Framework\TestCase */ public function testStandalonInputOutput() : void { - $this->template->setStandalone(true); - self::assertTrue($this->template->isStandalone()); + $this->template->isStandalone = true; + self::assertTrue($this->template->isStandalone); } /** @@ -157,8 +159,8 @@ final class TemplateTest extends \PHPUnit\Framework\TestCase */ public function testSourceInputOutput() : void { - $this->template->setSource(new NullCollection(4)); - self::assertEquals(4, $this->template->getSource()->getId()); + $this->template->source = new NullCollection(4); + self::assertEquals(4, $this->template->source->getId()); } /** @@ -172,6 +174,33 @@ final class TemplateTest extends \PHPUnit\Framework\TestCase self::assertEquals(TemplateDataType::GLOBAL_DB, $this->template->getDatatype()); } + /** + * @covers Modules\Helper\Models\Template + * @group module + */ + public function testTagInputOutput() : void + { + $tag = new Tag(); + $tag->setL11n('Tag'); + + $this->template->addTag($tag); + self::assertCount(1, $this->template->getTags()); + } + + /** + * @covers Modules\Helper\Models\Template + * @group module + */ + public function testNewestReportOutput() : void + { + TestUtils::setMember($this->template, 'reports', [ + $a = new NullReport(1), + $b = new NullReport(2), + ]); + + self::assertEquals($b, $this->template->getNewestReport()); + } + /** * @testdox Template data can be turned into an array * @covers Modules\Helper\Models\Template @@ -179,10 +208,10 @@ final class TemplateTest extends \PHPUnit\Framework\TestCase */ public function testToArray() : void { - $this->template->name = 'testName'; - $this->template->description = 'testDescription'; - $this->template->descriptionRaw = 'testDescriptionRaw'; - $this->template->setStandalone(true); + $this->template->name = 'testName'; + $this->template->description = 'testDescription'; + $this->template->descriptionRaw = 'testDescriptionRaw'; + $this->template->isStandalone = true; $array = $this->template->toArray(); $expected = [ @@ -211,10 +240,10 @@ final class TemplateTest extends \PHPUnit\Framework\TestCase */ public function testJsonSerialize() : void { - $this->template->name = 'testName'; - $this->template->description = 'testDescription'; - $this->template->descriptionRaw = 'testDescriptionRaw'; - $this->template->setStandalone(true); + $this->template->name = 'testName'; + $this->template->description = 'testDescription'; + $this->template->descriptionRaw = 'testDescriptionRaw'; + $this->template->isStandalone = true; $array = $this->template->jsonSerialize(); $expected = [ diff --git a/tests/depreciation/depreciation.cfg.json b/tests/depreciation/depreciation.cfg.json new file mode 100644 index 0000000..3505b5d --- /dev/null +++ b/tests/depreciation/depreciation.cfg.json @@ -0,0 +1,44 @@ +[ + { + "type": "label", + "attributes": { + "for": "amount" + }, + "default": { + "value": "Amount" + } + }, + { + "type": "input", + "subtype": "text", + "attributes": { + "id": "amount", + "name": "amount", + "type": "text" + }, + "default": { + "value": "10000" + } + }, + { + "type": "label", + "attributes": { + "for": "duration" + }, + "default": { + "value": "Duration" + } + }, + { + "type": "input", + "subtype": "text", + "attributes": { + "id": "duration", + "name": "duration", + "type": "text" + }, + "default": { + "value": "10" + } + } +] \ No newline at end of file diff --git a/tests/depreciation/depreciation.lang.php b/tests/depreciation/depreciation.lang.php new file mode 100644 index 0000000..f742733 --- /dev/null +++ b/tests/depreciation/depreciation.lang.php @@ -0,0 +1,27 @@ + [ + ':language' => 'English', + 'Depreciation' => 'Depreciation', + 'Period' => 'Period', + 'StraightLine' => 'Straight Line', + 'ArithmeticDegressive' => 'Arithmetic Degressive', + 'ArithmeticProgressive' => 'Arithmetic Progressive', + 'GeometricDegressive' => 'Geometric Degressive', + 'GeometricProgressive' => 'Geometric Progressive', + 'info' => 'The depreciation calculator shows the residual value at the end of the respective period (after depreciation). The geometric depreciation is calculated with a residual value of 10%.', + ], + 'de' => [ + ':language' => 'Deutsch', + 'Depreciation' => 'Abschreibung', + 'Period' => 'Periode', + 'StraightLine' => 'Linear', + 'ArithmeticDegressive' => 'Arithmetisch Degressiv', + 'ArithmeticProgressive' => 'Arithmetisch Progressiv', + 'GeometricDegressive' => 'Geometrisch Degressive', + 'GeometricProgressive' => 'Geometrisch Progressiv', + 'info' => 'Der Abschreibungsrechner zeigt den Restwert in der jeweiligen Periode (nach Abschreibung). Die geometrische Abschreibung ist mit einem Restwert von 10% berechnet.', + ], +]; diff --git a/tests/depreciation/logo.png b/tests/depreciation/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..27d7f3c7175f5db390881b4c82ea1f09b1a063cf GIT binary patch literal 90210 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%0DSFs;1ry|5t9vm^w*!cZD+e3kSNH3g3{$}c|3mrY zc-5IQOu)m?D!7>%Qx)Ix&DcIg1&Nc@dS3*u0Tm+jtp*m>hMC7=!SQA!GQZ>ePn{{P z6^s+=dNh)sMcvYKawL1$jRoBeCRq5o?Ke#cH5m5*NHy>y5pK#49F^Z+lt1=9l>I); zy)&oWNrNkWrx^S#4_3#7nuQ8>6;9cECxVIUMo1BI68~liCwYFx0*^MzER?T9$P!6| zA;MZmXLz_)wWFrMyPfVqa3bI;f$yDN;f5RlqIosMACc&k4BJ2wI&GK14&U361S2~p zlzRfRs%11WKNDd%AamiT0xQeTAG#kp{9lVwd&q5##(8ib+T;yAaH`9gKJnE>(89-B zQ0MJ1oLGyv2+&LCS_gh{^H2YQAjI;#)tSB|b>qyV1-|vKaY&;P@G67K3|%dD`+~ds zY}7S-$SKS$Zvt&Hh*>b8MQ7#QdjOp&GFhVbn>o}h_0`HH_SptxS)z+LoEEBT=>+2r z*JtakS65c1Y2{RFnTeHQ_=(u5l|gCAXw_IO46tWJ!vV1k4rp}4O38O;PHR;$)p!XB zkh;8L^6)U~6*t%3{uPBVthxo$$G>!>rk7v1pP?X__g%0e+QwbQjpp3+6-nv94G531l++UgP1ouh{k&I`b5ER{0GMGsQr~}h8~CfBv!!4ypNa8oLYMi< zy}zD8RTtr;wN;OW!LkUMYCORfIxV%TDtuz*8a_-`7%pv7*G6b!Qp9-_6l<=^#yhke z+&m<;gGSFNu>CJyA0!RXa@F1p4ws8~#V@4-4)yg8OP}K1?BUYPP*bVIa zU@-zgO#d;W@FAacLG#TauNR?ELcq~$E=jG zXqrO$#SV#$3)}6uul+q z`=4-%^?Jk26pxJy+J(ReWIT`DK-R(lMC$seH$r4TI21COSj~~C<1Mv}X)#gP5%`mL zyc~z-$~~96<1DM_00T*`UlbqtOF|kLJFqAWu--CBOb8|UTEg8gQ=kuKIXB9!4WlIA z6gqG391yaE4}d_bOsdII85%IRDTSX!s<@u`USaP0fGx!b?9kV&11mR`G+sQ%@Wy>UeUzGcIrD}~*);LM{zYiyu%UJ9W zMUVMr@u9NfwGwQLpGZ*yB7Wn^{=k-{MV6EyUb);8N{ZrvOv1E*caXYy^gZ2L&aLP1 zJc5>#x?^w4QgI@Nav^TI7PsJdnsx54CRy@e!bm+ENaTpnnVaAb)|)>c5={IpHVv}f zGD1*iod)O)wXtiB%l;XPf|}y_sNAmYl~#N0C54h^REveX>V54I>;E&xI_RDo4ZQqw zWV^-EnutCE1p=wngWl}{YgNJaH%MF0f0-kZWzE1FEUk#(Zp*u0?a;`0XQ;s*3;f_6YX;u>$nVpkbR~lpXf- zS2YsE7USG2W#t*a4GHTK$ggNWc(0LvjDuN6a5X4^_D4+D(0~ReU1X-EB;RyD%s(Bg zZKOlVb2-28$SvwG0ISX2Ps09Frrigh7+=+Lb?u*Rkb0E)^gekHNI|(MA>LR59%77N z&hTvp>$|&grZ)>;c0KuDj(=2;BRNtTxv1XvU}_-!pqc9q=)h|bf(FKa2S=>p+n0=e6aSz8b znzeLncwu%OEXjVF!>#xk!;vfKcd*-%x=CazbsaiqMrQiR;5qQa^{!>88P2jV$mc=; zoE?^gijTK%DOoZ(e^hZd=k(a{4V`{`P*Vs=@Dr>#G>*k>?{ngP$_b6cZcUbei6oe4GKE^&qrkS$wV> z@$lD>G}N(-dJU7KZR8u!rq2ZBTO_TdhxPqR-D_lv$IPQHwh>>7%YVMl=LsR{xknpF zmX?c!FHqtg+Yoj6^(KzRfSh8^|MOl9M%V_@2D{od*tv)fS@5_f6hL;8DZ-RBV+&xl z8l|X0R#|i*?i$%q@da1^(kzo@k-69F-bmzZ(HTW7{8O8!*W8*URB+;LDif3 zff0qcU2VuHZ~8vy_V=se>A~SsCUz!og{omF8DP1CduPBiyp3gugR~^0=cU9J&ml39vz~-Xr|zNY-F4Hrpo6 zS=JXRxOrG4L-$ANOQE^Uf0=B!^=|xTkI!vn92K09WM=X96E$4^(>R$ltA35t7pVV+ zohlC3RZray9Ct5F90(coCh#5vlwgm5{%$dpBcK|C%7)vBE>;P?3;qz23C4zbW%vKDu(KE2{oXOFAsd>C_fZSeOAV4HFZ!r-$a_s}?A<&iT_9-Iwx zR-(C=x>g`|V z0NQNwB%n>)R#}$0N0w;?6}E6! zd3^aPFs)DpG*4EP=w-?Xpkgb04B#*$soKhoRqEb_SZB*r%Ck{pg5RrO2aDcj@y2i! zrN7_P(&4H_qL-!6k@!;Y)lZrFt&+PO{W7(;`JqtaieUPrLE_geitm_m92cbA_im!h zq!Q8f_+Zj#N9}C{Ey%N~Y~LTKw(sjf7;sVCo90x_?Q2?jR#~0u9IUaIt0x?CXq^siI2wjxs)j^YRIKA z=KFC*fUG*w(&{CNK_9ws%Wo0i*q(Q4%O5U8w-Rvkfh*fw|xLP59rix99wOE{44S`F*<2 zVT*FDFh*gTlG9a=dY}x1t4}OwCQ{$@qWg7RBuLHe$oQgKtKb5TdwSm+4B;;LM3!!v zav!KdKW}-JsIG4> zvPNO^wPeusU)DE}rj^^5B2qD6dEge#&h$zRaH+zuo!BNFLF^Qy(S4Wi_)hYt2Knij3fGmlRWV$Wif z2EC-7Qd9wAaV+)|)W*h_kml9e@w!)Yn>H?uIJ8`Yi7uV0RHxFFV)Y+-GO^MK4z`!E zXnaMjrl;3IJZp{$|3y(bhY{xr`^(Q;M zePh;RJ&Fp-4LpY=61M`IZ!t5K zarZMCP?d5-v>seJ5h4O$1u!1>iNzu-ug0Z+d*Hl5;By+flBUYRzb#G_z=&~<_*#!Q zhYLib*v(xqZ>$`I^OXM!^L#mTxU?lG;BQ}6B6Z#Zl-qyXawY0(8=9!zzhi{NN=|MV z{CZn7ps^d8NxL^q*zv~@p>yqP(^x@1cR@#SUKj@gZkr_xL#>~}bixG_Et z_6DPw&F~PT9FVNy{r9gq;QmnWWoZ{{h+@)v>6e-0W z3bg3Wckg|k{D957GdnwH&Ypwe&W~qof%~VDQJw>NgN=C9{PVE}x&wl;FV!?%7TNhj zwwld9WxKKgIQIYE{H29Y=zQUyIrUrQxa%)?#oF)Eyh-*%&8)PW;rh!`65SNxY25Tj zPgHUhY^=T#_^F^CoM~-G(+6pEsa~@0X3hb~9t1!)q5fLJG=AFnQPA#})l&R0h2o{~#;hHTxAU~^Dh<%@Vq zBmW13JMb{+L=CZ2;=1CDYj8EH9JyYOYyM=aoVb7=4ZwD6mruQM`+J}2&Xv=6Faw1> zcsJlO|F8)hvEoct6Dt7~H;udK)*^5;S+XkwR3zb}C4Oe^eHpdiU*?<}K#w8cCUFm4 z^a<56jr4qR8PeQ6Ro3xH{&A~5n6aE{_6Pq=1)vc&*Vkn+Sy{~cM@e2&;NpJw zuq`{}ilZW`Rgaaq5;&+mbYei7_#j7o=0R6A0VKz!y&d%c%MY8_Wx(%bDRgF#45Ee) z=#2}J4F#pu27e@}GjAxPbhCOY^w!d~(X2J7J)FO_ypOu~&fv{sf*#rPcZD87PZsEC z9W>!eAMgQfRnDW0@V$XDxY;j4*-qB6_Z@x>vO1=7iu(7>eT<74Evb($1LBVe%lHCS^uKHd>MqnUqzUeWW@jIp7j z{H>EYTS2N7GGS7GZeD!6HuZ0T8%&40{n)4$TeuL_+`peusquEH->y61)@M-*X4+2G zxCDCqLaFgng$Q}a8gQK%?ridNpn#ni0$lI30OK@x8MQ2pLinE&o+(&f;CwdBKu$w1 zQQe}wlXVi|4L~p)pm~2Qu&%8?NiMwMM}&o9wBgI}Y1^JT)#3|x@U3;t*#?@byBSz7 zUgy8BkspHHaV0c(TMxhLMFZ@Tr>vj>YftXG)uZS$6b%!4sH!>dC$sA-tkSh}DprkS zBO({o8D~|S%VQvRtgvsw{@Q|h3AH-dqt#KH5t|#F&}$ED&@iVT zwWF5T5wmg@jUh89D#d4?oyYTSWDQ7MnPS9Z_wMblSwsP@6>A$tKvi%7dF(S9=Bxe7HF&7J*woj zs>If^(L=u#hjT_BKRCeL<9Z*L`j8Ef95x{{)KCHbX~BvBkXOA=VBBJn;br31t@hq@ zFHRC71`fJv#Ld80^<`P2D24toc-YT6sj0JXyab5#> z1Ps&8H8ONC_k{v#iXV&)M7$eod3K5>Rzo1|^OV>Lc62Ro9fWCD2can98Svs1bnQ6N zSRCFI%f%-|8_xH67S~IEsGOt=@)%WJSF#->+k#`btMov7iV7OS`c5ao_j> zY*p?VOT3h2_03R&&_;TUO!GyS8)74X-K4qc2LMf1X?Bu@j%WZx9d4uWo3z;HZi-Qr zakd0)R^!K=r9VH^0vx!{F(>Z%emd$;^o0bKMc;Fo#p^#6$(ra!!s&)Jmdc^@Jy7p1VJ;% zGv^9k7(vP`Np|xd&Fh{17julfy?~pVPTahVZH>&u4H8|i6t$1%_RMl`<1J9DBp+UWgvw8=W%!V%u%W6`KWd1i`B|Fm1gi z1EL!^flXf&t2r3sDN&Qo*4B!7% zN5u~`11wD}@(F|?<6B}CH>La_gqPlZ`*Da%`wmwK+T6!Q8O7WAS1iAy-6Q)i%pN`* z@;Vj;7~3`14#;O4g#L!LpCA9G)};Ir-C|{L|1hm)AZ}gO!&?TTbwGQ!>2PUDb~sN2 zeR?Y1U0RdS*8L}J6W`ktF4a0LM#)qeO8{sHMpYXNA#V>kkb!u}5WMZ)_Y_8B@_Vbp zT2*PF!}nc#_KURoZ_r{@L{9VvkyJpgXNA5u<{8c%zA6?)NpV~mCp-wQ&^C&6?N z{o>GLG1NCR3w0dRveYxQ(OGg#X}UM^3$dQC8B&p{=J)EUNZf7}x++R8n0tX3NL+DD z8|89XD@+YPa?PxVbkTA=%i5t!#QPS)@QhUXNKVF^p%sj%bpFJb7qY7*_fZS{FcEvC zhc0_p99>-AV~MSIcp^BZ+<_nG|5BXj>98Jea5VfV!;25oE5PF0GZ6ED%`Ze0D5ebV zmO2?flXH7&Bq^1Xts>o9T&Z3dgPQ?*#&yM|R-UL48nHL-PZy#OH8P*&4??inzpG#` zl>#x*spE2f1$b}4B&#A+w@o}ktMcuD@P`)m;TiMB>PXqiDd%V$p0Zrrc(jP*?)iKP zL{+v}hv0*2O92$&S)b!!1xMcn1 z4SniPA_Tnqh>i8RuIYrc%`PQS7IA^3QH?Q+-yLgbALR^huVe;^0J9;x6f>`Ny>Kg3TdWgSW2FzaiJ*TRJK^*qM6sB#i_YGuzR>YKT z$O=@({?giF29$Fm=e{YmJ}F3@^&s}5>m_tLE{{dC_e&hDUVwRpp!AJ8RVEQLtnAXf z9&|J>e6et}yBu`Vnn}?m?Lff~eOMQWg1SE;`-b8eDP+Hwb7!x=Xme6=%g#LIs=L~d zonH@$J}=Njw_p3wZams?6hcqaYK*h@n!R|myB+(eGdaQEzm6r2n4pbdj=v!ac|-HB zu#TPOd^RDr<=y^996zFU?x=`?3kQ_hIEj7!^WtBx;}J18t*_khVt+*MvI45bzMEr} zoiWcv1^-JbX?m&_z3=KraX;F%lCp4h*dKU{m5j)_g`tm*;PU6N(77L4(V6AtOx(sA zDN*nCP5KSQOZ*Jg2blV)!qPCK3~gQTiG>Hd)aS>@VBxz8H06gd&-AJKQ^OAQ1J_S03rO+~bl*N32J9P)}h+LZh9A~>{WL74f& z_r|9yRUx-;C<9me2Os`%eEg*qLTOq6@kmN+t-4uIh!nb$(@}uD>c8Zh^gmP6zQzs= zDPl?$?UT>{Ni$A$Zcl!vGDodF?jjgK>^}|@tW%$osY(Xgpk`_(Ucof{wAi9>*!+^! zF(Pc@;a0NmH*SOYl`bFF(m}!TsK?k^^3Xa}u*|e)FJR=Gt7V(hjPh zZM1UUIx~kDW8NJnYj1N#w#JY$icTT=!O;Nm%}aNQ*O%jv1f1>4Hqas8#?x^~_{y#G zW&2yKkP}yrs-R&yFH_5JRB>=ddcS%6P*~Hl=8c!Sr?qi~3N;nUe2Dj4MuR^$qqsUI zC8ATn9R4F<9uQqeNNa$tyULFs$PUs6FS_oK+4$CIgs`@=6Q{dmePW0q*A{!{<)af` zLSZp;tec}iHE1UD`0<%+DYpc0Vz`Tys3(>-96X+UO*XIPdMY! zK-Wpn83#XB_BjKcjS)9c7L9BM8+#EtL(?jj+_re zm`{~Rb{JV2EN%rWESg_9d$!_v^%Vy{F`~EayurGh&8nXUpt0H$t(i2B7c8z9Dqzy_ z=MTfpSNQt&F2+vN8ENyBE>CG5WIS%FgYjVpcehEC&vhJdikP@w5Uou2;jGJ`YNdJX z=`A8vhA*B0xW*?k$uK}p8QTs!$mebJxt$~2y-^#dGJ9{H_cPI#wkz9-70iP7RlrS? z@Y6s{GCiV66BLPR3yOCyN@T%t&OI+%S@ri%xR)^ZX*UCXfIiOKvE!Ln%w_pPSSro4 z|KHsE!CJ9M+Tm`va4^D}7L~rh6zVw4aNZjghN%7KRT5o#9GlR|{xctGY|Wdyu7ef! zZ5<l2$>B{#CaZ(!`(7B@U9$=q+`xTmV0xc>lz2 zevC7{*OFjP;7oKg5c!+EYAWWmS3efC42Z3F56L@MB~AB+3fM8}AIsHA(MGXbq$|A- zjVJZ|rFE1;(s~_BcA1-&R6>BruI*8+Iq}^`E3O&gV+CfA7(YegKry-^k(>y)E7HF% zkzH0JWtZp`x8t&rEa~&Yxa;H{iRYi}`>R%^^TAt`bATAc2q>0L{VNK);Qf~?ojf2X z8D-SU&`}e=ORIg_h%x!&O-)&l{~^WQ_x1~4nz5=b$Q*PC-&XL9AwZ5TUwaev9vCY; z9Zc)r-Yx=UAQ82=&&{nVu$@GKG-xCboI<07LTx@~F?$*hu!Sa=MA$6z3jVfv`V)LZ z*}~gsI-rq!cilY*dZP;Fc(cq<7=4G>>t8guz6vCQ z^pKC&nzHO5SQ0UI^+diC3pz(2`x<~PtP<{v;gXZYND>z(uFHxj>I1j@dE7G+fOw2+ z9v(mg^L#HD)=Bzwr7lwKM4c6w^f|37HUp2a>BQRlsZDSNSR>Npn{+0ST8%J4Gg-uT z@jDW=K;5ImRnn_oN^aFQOpU$xpW1qwyq)tc=*8j@YpuvO!M_5TDpi~%A43oeUVeR~ z4lA=I7xZ{Z5EjJ(>q8Qhf>E?WcA`hJ5BkXyoVU*^pnlxp^8ExbW(cJ_4_T<>qx+bE zm69lA_x6+B0(h)AE~YV7f{=&_?zif$c<0%M_>w43fGkTHiBLQyt=~mTWffvvEs_-d ztI(^?xUKx4&knuzGWZS-Bex_k+GF!$(rI*Od>rO4P)kuH1qgS!<*DG^|ufE(>eHj5gV zp}n!_6beXVo&lIJ9;ET(*rp-vONwWgLzf~m7r3D-ZU|gdz;1)XQG>;r5zlT;J->nk z9m02{|ID#XAHf8jM9B?PgVm4??nWGXg2`jM56pHS?J(cypkT=5UM^V5y+UypMdjC? zPZ`|{A2xA{WDqy7+?D{mg6w(A252LPddrIxHr{7uV*9PDn&3a3=MfyqO{6-~GsUsz zUvcN-evLTuA%g9|(Jq22B*1BaVz<>w^5XoQmEOylA+68w+W1#$O8?e!V{se!{Jzqp z;c8_|_^taVD$#&;AO)kMy<317uPSF?akB|6&?(`ro zh=WpxZyXy&wi|wSMzrC1(XXycRHdGrJ)(~_V|1W=N_cm~jP>Tr59gYizIbu~Zu!s6 zU@aznONa17ya1^h&HMgG1IITv-we=}b1Bt{JHS4X$vxB_#x0lM;%{n~ZO|_wT`7cO z2zXeB3+jr9!sW1bm{L*X-s|BCSRmdF^%6k5mkQWLuSV)e@M)bqmNYY`9~4vz5KOZ* z^uuzHsFcn@=Z`!DH4;FO1eX3PLZ!#6r>+{b2|+xV1irJ(TXr{Sfv1#yo*%-gZ*Z`~ zxyRi1>ZwkEk%;j3a&^|e#oELUudR5uqC*pMIyLI&Q+-~i9XQUtaIjRWBYV+|X0$Z3 z_b9+~gq;NgtNtc$3deMXEx`8-YS8?l~Vv1`zsl4)J{##r3yi2Fuj#{JZ<&X86MMJh1^ ze`C&i;KQ5#;~MFkAxk1v4%C!qGZaqNn4>9BJV9_yNe}sA2R|@l^n9mu*u{68R@R%C z`4mC${3;DN^D;7{A4!Z*noEnVL+F}|zx3N$@;*8=AA>-$_1M5g=B04H>n^94G80i^ zb3UZy13_glsksG``&+m*dyt&2K%Vm>vu;jF9d=Is^Y=C38cls)ro1|BLnMzmpf9p% z5(IH`sxV6KRd*Y%4bo^Rw}+0g3iYKhRYP^9kJ69JzC{xJ%-mHWgxkVOm!}we#;}69 zHU*2^7X6iV)FdLPeC(bRy12;HVc@UVOUyi<; zHzS$fG*C_aBF^Y-4&Q)q>?^O(+Mr27)n z3Id(TFHFCNQlgxS@Sm_}O{rEonvh#i84J&0j?brrU=#OwZWpI}t8K-dG2L!-s#P+#Z0h6g2nyevd`SXEz*kXXFL}ZPSUsmf$l!n-YtRfo_y0?p z)-2dZWzt}~oAhMZTS&yUX!Q0*>2tFhk8N| zm4b}co6awkTmL9e{hZ-eavQe63bdYT5RAQG&}6CmN(2jyGUGx}<)D{eyx=_sOH|{U z1H-TyFxgE?e#5iO|Krq>wGl%LJjMR; zcMw29@3CERV2fdiHgcNt+bUH-BA23^e3x z$>Hl~RwYnzaoY#Z`)nnKVH%Wtn5ynGmhqk&GqyLAhBG`QlWuRqhqOo8g&KXl2woH= z_rzT~{KUPeeGW1It_{t1YpoM^5_%85c`ww)XZ{Lf7S+#`O>`c9)zw$zaAG1nA-@Y? znBIG~^!IPPlF(H26_y{;U0v;}&MnE}w@p zqITbMN9+(OJ|x4|ahNm;pa|3I*uJad(owN~!7xU%HO>*YDav#yh&5DPw=1}HmFpyB zjs$?Xtm&ueBXQI^YPt*27J=bTY`!GMyitnLT&V5E@W%Xa_(LtvqdVNW;gu~T33(^o z9o*gqV`qi0N-dVIJZ<6oUpJmQc5elPdgnqvfHtx1Cerki`1U;Qj@3O@1t->jbXe4ub;Eo1>f7^x~^p~}w3k(I8* z@y69hA3>U@7QyP=x!mgiZI1MJ~@+3md zA#mDA{#F_)6OPhA*Ytpn`v9Kj4wM4|FjCc0TW%T>cFLN*sJdTOmBxu1XV2?ZS*6*~ z`Bey*(S^s*NlqSub*-Wl)xaIHd&5*Thu8uWGoQB`u&THZuA9`f_0l{~sjW^L!?*m{ z!Dp8tgR>(SIbnBMq^%U-oiI&ljKqG#%|1}?bDCo}Z&L-KiH`?jqo5K4u!`HH_Fh<& z&G9NsU(T^E?1$R2hts-`K77(i7Wx7UIy&?G)9veg?b#N5So2Wo zbWusqln3YiI_#E{+&7LNzw7w$8iI5}qp@t>$Uj=u1$O}Eh%gG@>_s@WY}H`Tr_LBf zX$b$0#?*#BY%I*QWy&IeB~}+QCMFN~VD zY(x95N+0II&bA>bK+6u^vjZ>P;5f7_)TDbDCIwAeh+U1rF|t?M<7n=~l{VQyq>@`z zZM_!Hzu4QkA@kj_jO@-vaHGJ4k*0|*pF?6%4i?zDR%km<=yQHAzDF3syz)mOBk&+! zEs;KdEzz|x+DI32ZH9L^tucieX*z_&dN=@ghQX{vV?@smme5>?%O#|Yikhid7kSjZ zN`f)(@qN>G)xAsE^32Goz2_2VkOCf`bevgic4Ag&PI01jQs2Gt@!&Bd)KYKnDg@XG zh2OPIrI6grBm1th&a%G4KIRAt1Q6^1Zi%$#5m3(Ff6p;Dkb?`k?cp<4&i}3w6+;m* zz1V>dXN46Ym}vaa)2zz8ze-f(R;lW{Q>?$!yul?z#vJem0ezoVPl65qNnCt5jxP8O zwXVDmQ=@=0QDb)N+D~6YDiB>X!0rcXL)1pkr#}k({~bZ_@55@52=}^vZfR|A z(CZ{VDhS*3sy`@^y(mknq3-vMzHQ`cv99CJZxKeJi~P=TyF2h_p-_q$X5EA%aP+iRb*fI?|_v=?%T6y((^u9ngLV#N(kC?*GTD-A`S{OtB)}AE% z3FVritt$olc(kwGly@`2hB#p&V1S!)4h1cnm&z5(zRWE^@n7v5u5jMkRJ}FqYc6|59>1V4Wq;#!jY#j9iP($t z?G4Yr%8kAnji^t++{|>S9k$Z<)WToO6vi_5taVZlg~sxg*tG&x$8bss$oW651%hYraZjI&4le_D^b>8JRgiE6VckXm;jX;dYr2jzs>&5^ z!qp;uqQv#6-4?otmQjWx(e{&2%2h_(Xjw^`R8M$aL~k)?FVH#0R{4SN;nma&Cr*0( zC8L4FVycyVnj90$lbDmik^hHT#Xp`c3tBP}v0eA?%w9PUn(9vLf2^1- zTAWY7YDn>>a^{lN&>2hTxp)oP0lwT3Z!pQ|Ijdsho`zAhDe3!AO?#{)%0|1cuR)-{ z@zbgXJTW^|1UcUf`oKMe_zR+(O$_C-e_NqMo?T<)LaTvA&8}%;^-_gduDg@*OP?OY za`Lc<_|0YYvZkJZ53Qv=DV=n+}0KWw?fF8K~zMo__TS8Y-NT7<1h$KY7`-Z}8dWb5Uo zxb3dKm!TcxbicL{oeh75leGJF?!R3^h^N4H>naZi2)aXZDTe&r?2^qwn|qKugKFoP za;8?QkZU<;Q#^h$D=SZJ4u4cz4q%zHTLb;VWG@mlD)RMpOR}6cTp3rX!1ze6vDr+{ zt_5LU+a&MQ|7}PY4hr9pbx9HWdX5K^$i{~rEm$!(-n*asS1xS*tlPTH3E9aHI_H_J z=p()ii^xXC3iTrNTS__&F<6C|S>EuW)~6>fHfwl)sLx7XG!6}n(vtysRm-Q4egBYG zM~i8M_Ye*Jt=khd+-3-N9jU~fyEY6KCk_7*X(+^rkU2fc+{uh89ALCx$5`>;jsng1y;MR^V=O0tm zKm0hJ;dwH_UQdWT);HxB@)pI8fTGUt=y^Ezhgsdbvvl=MAmoe+En-`5s4GmZbU2UU zZFGqK#;^Tm1w@veBvLksJ`r+tP!01}RG)PT&|fxG7f@%bXhvf*kZY_1b|EBNW--;3 zS?f`nF%jLT7&>83b&{dxq)nahM*{v4#=VEnzlOfXNkjHQ+f+&{QNla9N|3r}*PU1r z>QEB~%nx`i!cVsceS7wqv%P-{Pa24{sY@l{r7baA$sH9P;1tcn@LkrX@@MG}GjOwn zzax^f=q(Zaceo-7VdbYs;5SG5B3QQVCQ;Ck<^gUspmhk74{>T^o=~ln%CHLs%=GEC z2)3VhTmh4neRzn#sk-2-2%umm2HcEYSPc1FoNQ=RWehgoX+B`%om5+;%N2;_R%omRW7djLM)3wXjzS6qZr(Q>| z{a#01NBXp%>c6I!4VPU;TnHoH%LuZW4S~QVM!nJo1kce3J{$)?P`u1oAE=q`tg?kZ zg^;kjfT!+eV@3LI>gzYIa{SJupRAKve||)B+INHxv|nER*dZR$$U8xxZKIK{Z{r`_ zUCmLVC7NU3HXwHzz^!0^pN~dh?SJ2w??4&U-M806ptM_TMhCfxFgL@{4CNdx!VP`X zD)2P{zeT~A02VvNgG`v0yl%we&KeCt}h8WtIasA!0n;zfjaa%5vr-a20|gP?Vy|jZC^ckWJMv><|FtHKjgATEY9{ zQz5_K)@|NK-Lr&#>8_c6fjD0eJnmmd^Jmk4d%--iGkHm4(xNarBR?IJ8$9816naKL$e3Vx zgrZH8q8!XZBGKc<>vSdVM>ytck%1L^Ic3P;E`R7T2V{#MeR#J?i0}V;hM}GodF2s% zCjw-jyn(5LO1*!ABKNhB1`CJ}k(qdYuBCoDQA`;Dv@F%G&=+kvnHH4}N|2GyjGw%q zMA`=RZ4l9^vE8N;f4n-5mDv0mzE2_+0NaC4c{dWL3gJS4MXz&tlSrSQ{Wc@59$&LJ z!i<|qf#mz|YjKBKv>YztO@2v$bw#4vJWV-Ii_4lJo!|{^vEvbW~=wt53dSCtn%^y3)?B!yvOVJMJaaK0Q!Ulv( z1^oryvnghT-eGS&{kOJ|c$1)_jb(TM;+{w`vO&ticBOdJZy5nISOi{j zxH0eZJVAEE5ueI%o+Qb!8z7lKiw@d`-1v#0vMaH7wh$5cP7X~QQ0gK-$()u#OON3I z;6kj+@3;v%-^qQ&YkrW+#)V5njF1`ii$5JqRnQEb+oG-P%GeiULyL40r7dw7oj7op znGO|}`??2p2fAuAoWfaKi1ZlFe^h@6P@M39&g7Kg$F&{>86f0*q;5Av-bSrReLErk zcoOHF@E^RDuHhav*KQPT+)1V{v7w_t(>NA^8~BgA5k^MO%5-0qQ+#n|VfWo|>fr6e zdD*(Ys=-yudd<=?JT(u(MN7mJ0)i!MqHY!3fQAxGi+H6w~+$kL!Gg z&=Iu*%j>Pxg6E$y%zpKj-1i}9PQ=bFB1++e85*LS49Q-9E)?l1RuX*3axB}*yAb^L zSbxv965gHw8xYC3*B7(hZ`|bmXe1|M+W1bO-bMz$9_19{$NgyT5-gMb{H&4+SwT<@ z)IR5rK}=q2Rj&AWFArCwy|KJn@~b9L_V~4)!#)MQHIprv**KW^#)*bN5MG}3e&`zJ zGFMIko+m4^b@taT z0YpEUDV%Hy5UVf1!OSX%tq3b#--BEOw7Sp_ggUtlukX^`#eG&O10n zKp7jqa{H~H!5p^bPd?a-xov_XT(AO1%4x^Zpg(RDF?HS|3bnzkC7SuuE2Gm44M0^3 zES$@>m6SM@wSY5=)CO6Ls1Na~tSdwg7F@s?&N+!XeKK~zTl58@>mXx>f+((@fQYt*#vhF@d{ zBfEPNJ(}}Bp8&C=%3@k<-Ca<%L}@WxL=lAF{a>q7#yz87jf9CpjxA_@sb6;atw&-$ zoq+Z%TpzJC7lQ45YaXNS9MfR19mk?5*?H-L?QXM&>2TEXCDo3IhnC4~tu{(3wX#oh__tsWhmXydP>&tLo%y@_`L&I4{(tdf4LAhfNce%53VDB zUOc_p-IiYU87%Oipn1)>>7-t@YQH5uu^g-BFnHJ-c;hE9u&pr zvM3WL(#NGUiJlyUPUcupI;L;u{`(MtSSy%zjR)$UH^r)SI_?dQa&otR_IH2G9NW6w zl_7I`t7x(ZABTGR;1H=FlF4n)wm*AcXUNQIeL5AYqzNYYP#7$1EQV{zwaN)}PSy+6 zdn*w3Nvs{DKyC#rJ4W8-~OI)@53LI!r9qdRd0%F{)Af9>8p*xd_ZhA!Nh71zN^2pR1LMF z&;}ZJ%vZq^i<heL8_=pMpz^W{nEOrx+V%W@bhXANW2hOuR|Bp2B2OTV~eVcVBh9x%H%T+hwNf zSKWQPa{f@jaO8V(ds1cAe*V1V-fGRGD)O@g$}e3GZz^0uK1-EP#+$KE+Nfg_C4|R< z^_{{rt(fcnp3r46qh$O0IVc=}*=pFJE_hT45Rlp{tI+-ZQ1Rd!rx6h9XGX65eNm&m z1D&(*N^==C3{Ziu7FDVNqbS9Fke6`m2wt|E1uun%!tWSey%890tZX%>YT_2Yg-gVQ zUtboLsJHV$hF`F6Ikj#;e}#5x6>$u%%++_R_`BOJU|$Jx+aFc`KfNHmOq(eYUCP;A z+qE3#m^U!zlL4eR=8ipkrx$UoZPHmnhlANM`4QUy1qO)St<(UU3;th@!*_t9yBoHu z0pwH{bBE!UF^^qloo}p@NGv{Xs^Z69ot|zJFsBY)`sS{0tLp+TJ zNR1QyVKGBuD6{mxa7CimRkPk0I<1V&^>8ESbQG4+{srTjCG2!XwU)6Y(ZkU6>VHrOi%l#p$Z;UV7%L?fi7!RGlT%Y3!Da{xm+mjA6~QyI4b zx=^($%dY^_4LQ#5Rv?P_dGBNFr?&d9sdbWC1&?F*del-VWjsTQ7=mLpx0XBe*^=U` ziTRYS4`&o8S(w2G0X}Vrw*0YM(!!x7QseocY@tdIQnrgk4ym!^&OxhDHFNcJ%yOsq ze65LMgZ}weYq0eB5BPg=jjaxSG&)M;Op|)zca|;eOVdCv-K+7B)LqZ-_4{}V?zwZK zi0n&_VB3zFc;4NyX&>(nWQDN+5LH5b`u2o?@9Q_?w2_`v{gejM@{D9+YQ0O zNiDS_*^+gFWJB-+Km0T%E6t?P0+B)2fi8wPM~X~vV0u+2R{cU{>q7M2m4*#R>d^sR z@W1~wX)zIs!EPAI;&F%8`tr;2$LlW2QdeqyvizKdl4B`Ns#IApQ3wXZ5=iLy~Pz7B(UOE}%*OV0tu2Jc~0Bnl6_iP@jQW<&o)*=>BH2_N@>(t}@x&oLOEWeDwc z#DALVRjMpMVKnJlO%1(Y>mMkey0AZnQB@uMp@19x_`Q4LX!w@XWlTc&@hqqVn&xxm zc3EDi;C^h568s35{M>A{A5Lb%S}x~un!%oj-4?^%8>jG2#YlZ|xLJM&|Fin3O_gA} zdZ=A+PE2@Q{uV|#)fuzS&d&F+v<*caD5{#0P@TD|`m8xE?@6GzKr@oVmfD@Oz%%uk zfAjYH6?=p2J%`Wnx?_#|)9>5FDzxc8D&qavzpO^m)QMm6BuEG0=um@p|NhMF+w#6b zkuHATz;Shq7aU=Op9Zz|1D?bA4$%`WAq6kq=Xxib9$h^i_e8AEn&sFQak|pXdb!E*s?Z++Q~eM%>?ip7k5f?G)9lRIx~r4R;K0Yfk-`D`mx!vOTd6$rW8` z)-@X~0{ETud4iG+xs^L zo3er0U)`i1)s&39%LfXYVo>A$7@gglmt_;>uXZXbj8V1q>dg(Fe;zG-#@e$DIV`3{ z${}>p}lXYMZu3~uFHKtM#OxIFf4Ll z=@rK`vTWFUwpZ6bv&=~*tM$cw$1Gk++Rx_#^vZc=)6j87vvqfro2G>9fJFKWZLn!4 z_8+RPw(O#IxvYrJ%(dVBds*uV8kzKiDP<0d5(+y+l6?1|`lsZkHFO6b-7D2r9efqo z`&T^cjn?6!LX>H8y&c)OV^f&Ed5?>4FGO#DNx+wn+z2y1tP{Ex$pqE-ZF1ZqQbiZQ$dNBkXyB^C^>as#Vif zaCwp4en�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'tcoll'); +$rcoll = $this->getData('rcoll'); +$cLang = $this->getData('lang'); +$template = $this->getData('template'); +$report = $this->getData('report'); +$basepath = \rtrim($this->getData('basepath') ?? '', '/'); + +/** @noinspection PhpIncludeInspection */ +$reportLanguage = include $basepath . '/' . \ltrim($tcoll['lang']->getPath(), '/'); +$lang = $reportLanguage[$cLang]; + +$amount = (float) ($this->request->getData('amount') ?? 10000.0); +$duration = (int) ($this->request->getData('duration') ?? 10); + +$depreciation = [ + [ + $lang['Period'], + $lang['StraightLine'], + $lang['ArithmeticDegressive'], + $lang['ArithmeticProgressive'], + $lang['GeometricDegressive'], + $lang['GeometricProgressive'], + ], +]; + +for ($i = 1; $i <= $duration; ++$i) { + $depreciation[] = [ + $i, + $this->getCurrency(Depreciation::getStraightLineResidualInT($amount, $duration, $i), 'medium', ''), + $this->getCurrency(Depreciation::getArithmeticDegressiveDepreciationResidualInT($amount, 0.0, $duration, $i), 'medium', ''), + $this->getCurrency(Depreciation::getArithmeticProgressiveDepreciationResidualInT($amount, 0.0, $duration, $i), 'medium', ''), + $this->getCurrency(Depreciation::getGeometicProgressiveDepreciationResidualInT($amount, 0.0, $duration, $i), 'medium', ''), + $this->getCurrency(Depreciation::getGeometicDegressiveDepreciationResidualInT($amount, $amount * 0.1, $duration, $i), 'medium', ''), + ]; +} + +$out = \fopen('php://output', 'w'); +foreach ($depreciation as $d) { + \fputcsv($out, $d); +} +\fclose($out); diff --git a/tests/depreciation/view.doc.php b/tests/depreciation/view.doc.php new file mode 100644 index 0000000..d5d9e8f --- /dev/null +++ b/tests/depreciation/view.doc.php @@ -0,0 +1,190 @@ +getData('tcoll'); +$rcoll = $this->getData('rcoll'); +$cLang = $this->getData('lang'); +$template = $this->getData('template'); +$report = $this->getData('report'); +$basepath = \rtrim($this->getData('basepath') ?? '', '/'); + +/** @noinspection PhpIncludeInspection */ +$reportLanguage = include $basepath . '/' . \ltrim($tcoll['lang']->getPath(), '/'); +$lang = $reportLanguage[$cLang]; + +$date = new \phpOMS\Stdlib\Base\SmartDateTime($this->request->getData('date') ?? 'Y-m-d'); + +$languageEnGb = new Language(Language::EN_GB); + +$phpWord = new PhpWord(); +$phpWord->getSettings()->setThemeFontLang($languageEnGb); + +$section = $phpWord->addSection([ + 'marginTop' => 0, + 'marginRight' => 0, + 'marginBottom' => 0, + 'marginLeft' => 0, +]); + +$section->addImage( + __DIR__ . '/logo.png', + [ + 'width' => (int) Converter::cmToPixel(5), + 'height' => (int) Converter::cmToPixel(5), + 'wrappingStyle' => 'square', + 'positioning' => Image::POSITION_ABSOLUTE, + 'posHorizontal' => Image::POSITION_HORIZONTAL_CENTER, + 'posHorizontalRel' => Image::POSITION_RELATIVE_TO_PAGE, + 'posVerticalRel' => Image::POSITION_RELATIVE_TO_PAGE, + 'posVertical' => Image::POSITION_VERTICAL_CENTER, + ] +); + +$fontStyleName = 'splashStyleF'; +$phpWord->addFontStyle($fontStyleName, [ + 'size' => 32, 'color' => '3697db', +]); + +$paragraphStyleName = 'splashStyleP'; +$phpWord->addParagraphStyle($paragraphStyleName, [ + 'alignment' => Jc::CENTER, + 'spaceBefore' => 6000, +]); + +$section->addTextBox( + [ + 'width' => (int) Converter::cmToPoint(20), + 'height' => (int) Converter::cmToPixel(5) + 200, + 'borderSize' => -1, + 'size' => 32, 'color' => '3697db', + 'positioning' => Image::POSITION_ABSOLUTE, + 'posHorizontal' => Image::POSITION_HORIZONTAL_CENTER, + 'posHorizontalRel' => Image::POSITION_RELATIVE_TO_PAGE, + 'posVerticalRel' => Image::POSITION_RELATIVE_TO_PAGE, + 'posVertical' => Image::POSITION_VERTICAL_CENTER, + ] +)->addText('Demo Report', $fontStyleName, $paragraphStyleName); + +$paragraphStyleName = 'pStyle'; +$phpWord->addParagraphStyle($paragraphStyleName, [ + 'alignment' => Jc::CENTER, 'spaceAfter' => 100, +]); + +$phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]); + +$section = $phpWord->addSection([ + 'marginTop' => 1000, + 'marginRight' => 1000, + 'marginBottom' => 1000, + 'marginLeft' => 1000, +]); + +$titleFontStyleName = 'titleStyleF'; +$phpWord->addFontStyle($titleFontStyleName, [ + 'size' => 24, 'color' => '000000', +]); + +$titleParagraphStyleName = 'titleStyleP'; +$phpWord->addParagraphStyle($titleParagraphStyleName, [ + 'spaceAfter' => 100, +]); + +$section->addText('Demo Report - ' . $date->format('Y-m-d'), $titleFontStyleName, $titleParagraphStyleName); +$section->addShape('line', [ + 'points' => '0,0 ' . ((int) Converter::cmToPoint(19)) . ',0', + 'outline' => [ + 'color' => '#3697db', + 'line' => 'thickThin', + 'weight' => 1, + 'startArrow' => '', + 'endArrow' => '', + ], +]); + +$section->addTextBreak(1); + +$listFontStyleName = 'listStyleF'; +$phpWord->addFontStyle($listFontStyleName, [ + 'size' => 16, 'color' => '000000', +]); + +$listParagraphStyleName = 'listStyleP'; +$phpWord->addParagraphStyle($listParagraphStyleName, [ + 'spaceAfter' => 300, +]); + +$section->addListItem('Create custom localized reports', 0, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('They are 100% customizable in terms of style, layout and content', 0, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('You can export them as:', 0, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('Excel', 1, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('PDF', 1, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('Print', 1, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('PowerPoint', 1, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('CSV', 1, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('Word', 1, $listFontStyleName, null, $listParagraphStyleName); + +$section = $phpWord->addSection([ + 'marginTop' => 1000, + 'marginRight' => 1000, + 'marginBottom' => 1000, + 'marginLeft' => 1000, +]); + +$section->addText('Ideas for helpers', $titleFontStyleName, $titleParagraphStyleName); +$section->addShape('line', [ + 'points' => '0,0 ' . ((int) Converter::cmToPoint(19)) . ',0', + 'outline' => [ + 'color' => '#3697db', + 'line' => 'thickThin', + 'weight' => 1, + 'startArrow' => '', + 'endArrow' => '', + ], +]); + +$section->addTextBreak(1); + +$section->addListItem('Reports (e.g. sales, finance, marketing)', 0, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('Mailing generator based on pre-defined layouts', 0, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('Document generator based on pre-defined layouts', 0, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('Calculators (e.g. margin and price calculators)', 0, $listFontStyleName, null, $listParagraphStyleName); + +$section = $phpWord->addSection([ + 'marginTop' => 1000, + 'marginRight' => 1000, + 'marginBottom' => 1000, + 'marginLeft' => 1000, +]); + +$section->addText('Data Source', $titleFontStyleName, $titleParagraphStyleName); +$section->addShape('line', [ + 'points' => '0,0 ' . ((int) Converter::cmToPoint(19)) . ',0', + 'outline' => [ + 'color' => '#3697db', + 'line' => 'thickThin', + 'weight' => 1, + 'startArrow' => '', + 'endArrow' => '', + ], +]); + +$section->addTextBreak(1); + +$section->addListItem('You can provide data for the helpers in many different ways', 0, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('Manual user input', 1, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('File upload (e.g. excel, csv)', 1, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('Database upload (e.g. sqlite)', 1, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('Database connection to local or remote database', 1, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('External APIs', 1, $listFontStyleName, null, $listParagraphStyleName); +$section->addListItem('Internal APIs (everything from the Orange Management backend)', 1, $listFontStyleName, null, $listParagraphStyleName); + +$writer = IOFactory::createWriter($phpWord, 'Word2007'); +$writer->save('php://output'); diff --git a/tests/depreciation/view.json.php b/tests/depreciation/view.json.php new file mode 100644 index 0000000..8dbae95 --- /dev/null +++ b/tests/depreciation/view.json.php @@ -0,0 +1,3 @@ +getData('lang'); +/** @noinspection PhpIncludeInspection */ +$reportLanguage = include $basepath . '/' . \ltrim($tcoll['lang']->getPath(), '/'); +$lang = $reportLanguage[$cLang]; + +$amount = (float) ($this->request->getData('amount') ?? 10000.0); +$duration = (int) ($this->request->getData('duration') ?? 10); + +$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); + +$pdf->SetCreator('Dennis Eichhorn'); +$pdf->SetAuthor('Dennis Eichhorn'); +$pdf->SetTitle('Demo Mailing'); +$pdf->SetSubject('Mailing'); +$pdf->SetKeywords('demo helper mailing'); + +$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); + +$pdf->SetMargins(PDF_MARGIN_LEFT, 15, PDF_MARGIN_RIGHT); +$pdf->SetAutoPageBreak(false, 0); +$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); + +$pdf->setPrintHeader(false); +$pdf->setPrintFooter(false); + +$pdf->AddPage(); + +$pdf->SetFillColor(52, 58, 64); +$pdf->Rect(0, 0, $pdf->getPageWidth(), $pdf->getPageHeight(), 'F'); + +$pdf->SetFillColor(54, 151, 219); +$pdf->Rect(0, 0, $pdf->getPageWidth(), 5, 'F'); + +$pdf->SetFont('helvetica', '', 32); +$pdf->SetTextColor(54, 151, 219); +$pdf->Write(0, 'Demo Mailing - ' . $this->request->getData('date') ?? 'Y-m-d', '', 0, 'C', true, 0, false, false, 0); + +$pdf->Image(__DIR__ . '/logo.png', $pdf->getPageWidth() / 2 - 60 / 2, 40, 60, 60, 'PNG', '', 'C', true, 300, '', false, false, 0, false, false, false); + +$pdf->SetFillColor(67, 74, 81); +$pdf->Rect(0, 110, $pdf->getPageWidth(), 145, 'F'); + +$html = ' + + + + + + + + '; + +for ($i = 1; $i <= $duration; ++$i) { + $html .= ''; + $thml .= ''; + $thml .= ''; + $thml .= ''; + $thml .= ''; + $thml .= ''; + $thml .= ''; + $thml .= ''; +} + +$html = '
' . $lang['Period'] . '' . $lang['StraightLine'] . '' . $lang['ArithmeticDegressive'] . '' . $lang['ArithmeticProgressive'] . '' . $lang['GeometricDegressive'] . '' . $lang['GeometricProgressive'] . '
' . $i . '' . $this->getCurrency(Depreciation::getStraightLineResidualInT($amount, $duration, $i), 'medium', '') . '' . $this->getCurrency(Depreciation::getArithmeticDegressiveDepreciationResidualInT($amount, 0.0, $duration, $i), 'medium', '') . '' . $this->getCurrency(Depreciation::getArithmeticProgressiveDepreciationResidualInT($amount, 0.0, $duration, $i), 'medium', '') . '' . $this->getCurrency(Depreciation::getGeometicProgressiveDepreciationResidualInT($amount, $amount * 0.1, $duration, $i), 'medium', '') . '' . $this->getCurrency(Depreciation::getGeometicDegressiveDepreciationResidualInT($amount, $amount * 0.1, $duration, $i), 'medium', '') . '
'; + +$pdf->SetXY(15, 125); +$pdf->SetFont('helvetica', '', 14); +$pdf->SetTextColor(255, 255, 255); +$pdf->writeHTML($html, true, false, true, false, ''); + +$pdf->SetFont('helvetica', '', 12); +$pdf->SetXY(15, 262); +$pdf->SetTextColor(54, 151, 219); + +$text = <<Write(0, $text, '', 0, 'L', true, 0, false, false, 0); + +$pdf->Output('mailing.pdf', 'I'); diff --git a/tests/depreciation/view.ppt.php b/tests/depreciation/view.ppt.php new file mode 100644 index 0000000..e96c477 --- /dev/null +++ b/tests/depreciation/view.ppt.php @@ -0,0 +1,333 @@ +getData('tcoll'); +$rcoll = $this->getData('rcoll'); +$cLang = $this->getData('lang'); +$template = $this->getData('template'); +$report = $this->getData('report'); +$basepath = \rtrim($this->getData('basepath') ?? '', '/'); + +/** @noinspection PhpIncludeInspection */ +$reportLanguage = include $basepath . '/' . \ltrim($tcoll['lang']->getPath(), '/'); +$lang = $reportLanguage[$cLang]; + +$date = new \phpOMS\Stdlib\Base\SmartDateTime($this->request->getData('date') ?? 'Y-m-d'); + +$objPHPPresentation = new PhpPresentation(); + +$objPHPPresentation->getDocumentProperties()->setCreator('Orange Management') + ->setLastModifiedBy('Orange Management') + ->setTitle('Orange Management - Demo Report') + ->setSubject('Orange Management - Demo Report') + ->setDescription('Demo') + ->setKeywords('demo helper report') + ->setCategory('demo'); + +$colorBlack = new StyleColor('FF000000'); +$colorBlue = new StyleColor('FF3697db'); +$colorDark = new StyleColor('FF434a51'); + +// start screen +$oSlide1 = $objPHPPresentation->getActiveSlide(); +$oBkgColor = new Color(); +$oBkgColor->setColor($colorDark); +$oSlide1->setBackground($oBkgColor); + +$shape = new File(); +$shape->setName('Company Logo') + ->setDescription('Company Logo') + ->setPath(__DIR__ . '/logo.png') + ->setHeight(300) + ->setOffsetX(320) + ->setOffsetY(120); +$oSlide1->addShape($shape); + +$shape = $oSlide1->createRichTextShape() + ->setHeight(300) + ->setWidth(600) + ->setOffsetX(180) + ->setOffsetY(450); +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); +$textRun = $shape->createTextRun('Demo Report'); +$textRun->getFont()->setBold(true)->setSize(35)->setColor($colorBlue); + +// first slide +$oSlide2 = $objPHPPresentation->createSlide(); + +$shape = $oSlide2->createRichTextShape() + ->setHeight(25) + ->setWidth(960) + ->setOffsetX(0) + ->setOffsetY(0); + +$shape->getFill() + ->setFillType(Fill::FILL_SOLID) + ->setStartColor($colorBlue) + ->setEndColor($colorBlue); + +$shape = $oSlide2->createRichTextShape() + ->setHeight(75) + ->setWidth(860) + ->setOffsetX(50) + ->setOffsetY(65); + +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT); +$textRun = $shape->createTextRun('Demo Report - ' . $date->format('Y-m-d')); +$textRun->getFont()->setBold(false)->setSize(35)->setColor($colorBlack); + +$line = new Line(50, 130, 910, 130); +$line->getBorder()->setColor($colorBlue); +$oSlide2->addShape($line); + +$shape = $oSlide2->createRichTextShape(); +$shape->setHeight(600) + ->setWidth(930) + ->setOffsetX(10) + ->setOffsetY(170); + +$shape->getActiveParagraph() + ->getAlignment() + ->setHorizontal(Alignment::HORIZONTAL_LEFT) + ->setMarginLeft(50) + ->setIndent(-25); + +$shape->getActiveParagraph()->getFont()->setSize(21)->setColor($colorBlack); +$shape->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET)->setBulletChar('•'); + +$shape->createTextRun('Create custom localized reports'); +$shape->createParagraph() + ->getAlignment() + ->setLevel(1) + ->setMarginLeft(150) + ->setIndent(-25); + +$shape->createParagraph()->getAlignment()->setLevel(0)->setMarginLeft(50)->setIndent(-25); +$shape->createParagraph()->getAlignment()->setLevel(0)->setMarginLeft(50)->setIndent(-25); + +$shape->createTextRun('They are 100% customizable in terms of style, layout and content'); +$shape->createParagraph() + ->getAlignment() + ->setLevel(1) + ->setMarginLeft(150) + ->setIndent(-25); + +$shape->createParagraph()->getAlignment()->setLevel(0)->setMarginLeft(50)->setIndent(-25); +$shape->createParagraph()->getAlignment()->setLevel(0)->setMarginLeft(50)->setIndent(-25); + +$shape->createTextRun('You can export them as:'); +$shape->createParagraph() + ->getAlignment() + ->setLevel(1) + ->setMarginLeft(150) + ->setIndent(-25); + +$shape->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET)->setBulletChar('◦'); +$shape->createTextRun('Excel'); +$shape->createParagraph()->createTextRun('PDF'); +$shape->createParagraph()->createTextRun('Print'); +$shape->createParagraph()->createTextRun('PowerPoint'); +$shape->createParagraph()->createTextRun('CSV'); +$shape->createParagraph()->createTextRun('Word'); + +$shape = new File(); +$shape->setName('Company Logo') + ->setDescription('Company Logo') + ->setPath(__DIR__ . '/logo.png') + ->setHeight(50) + ->setOffsetX(880) + ->setOffsetY(650); +$oSlide2->addShape($shape); + +// second slide +$oSlide3 = $objPHPPresentation->createSlide(); + +$shape = $oSlide3->createRichTextShape() + ->setHeight(25) + ->setWidth(960) + ->setOffsetX(0) + ->setOffsetY(0); + +$shape->getFill() + ->setFillType(Fill::FILL_SOLID) + ->setStartColor($colorBlue) + ->setEndColor($colorBlue); + +$shape = $oSlide3->createRichTextShape() + ->setHeight(75) + ->setWidth(860) + ->setOffsetX(50) + ->setOffsetY(65); + +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT); +$textRun = $shape->createTextRun('Ideas for helpers'); +$textRun->getFont()->setBold(false)->setSize(35)->setColor($colorBlack); + +$line = new Line(50, 130, 910, 130); +$line->getBorder()->setColor($colorBlue); +$oSlide3->addShape($line); + +$shape = $oSlide3->createRichTextShape(); +$shape->setHeight(600) + ->setWidth(930) + ->setOffsetX(10) + ->setOffsetY(170); + +$shape->getActiveParagraph() + ->getAlignment() + ->setHorizontal(Alignment::HORIZONTAL_LEFT) + ->setMarginLeft(50) + ->setIndent(-25); + +$shape->getActiveParagraph()->getFont()->setSize(21)->setColor($colorBlack); +$shape->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET)->setBulletChar('•'); + +$shape->createTextRun('Reports (e.g. sales, finance marketing)'); +$shape->createParagraph() + ->getAlignment() + ->setLevel(1) + ->setMarginLeft(150) + ->setIndent(-25); + +$shape->createParagraph()->getAlignment()->setLevel(0)->setMarginLeft(50)->setIndent(-25); +$shape->createParagraph()->getAlignment()->setLevel(0)->setMarginLeft(50)->setIndent(-25); + +$shape->createTextRun('Mailing generator based on pre-defined layouts'); +$shape->createParagraph() + ->getAlignment() + ->setLevel(1) + ->setMarginLeft(150) + ->setIndent(-25); + +$shape->createParagraph()->getAlignment()->setLevel(0)->setMarginLeft(50)->setIndent(-25); +$shape->createParagraph()->getAlignment()->setLevel(0)->setMarginLeft(50)->setIndent(-25); + +$shape->createTextRun('Document generator based on pre-defined layouts'); +$shape->createParagraph() + ->getAlignment() + ->setLevel(1) + ->setMarginLeft(150) + ->setIndent(-25); + +$shape->createParagraph()->getAlignment()->setLevel(0)->setMarginLeft(50)->setIndent(-25); +$shape->createParagraph()->getAlignment()->setLevel(0)->setMarginLeft(50)->setIndent(-25); + +$shape->createTextRun('Calculators (e.g. margin calculator)'); +$shape->createParagraph() + ->getAlignment() + ->setLevel(1) + ->setMarginLeft(150) + ->setIndent(-25); + +$shape = new File(); +$shape->setName('Company Logo') + ->setDescription('Company Logo') + ->setPath(__DIR__ . '/logo.png') + ->setHeight(50) + ->setOffsetX(880) + ->setOffsetY(650); +$oSlide3->addShape($shape); + +// third slide +$oSlide4 = $objPHPPresentation->createSlide(); + +$shape = $oSlide4->createRichTextShape() + ->setHeight(25) + ->setWidth(960) + ->setOffsetX(0) + ->setOffsetY(0); + +$shape->getFill() + ->setFillType(Fill::FILL_SOLID) + ->setStartColor($colorBlue) + ->setEndColor($colorBlue); + +$shape = $oSlide4->createRichTextShape() + ->setHeight(75) + ->setWidth(860) + ->setOffsetX(50) + ->setOffsetY(65); + +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT); +$textRun = $shape->createTextRun('Data Source'); +$textRun->getFont()->setBold(false)->setSize(35)->setColor($colorBlack); + +$line = new Line(50, 130, 910, 130); +$line->getBorder()->setColor($colorBlue); +$oSlide4->addShape($line); + +$shape = $oSlide4->createRichTextShape(); +$shape->setHeight(600) + ->setWidth(930) + ->setOffsetX(10) + ->setOffsetY(170); + +$shape->getActiveParagraph() + ->getAlignment() + ->setHorizontal(Alignment::HORIZONTAL_LEFT) + ->setMarginLeft(50) + ->setIndent(-25); + +$shape->getActiveParagraph()->getFont()->setSize(21)->setColor($colorBlack); +$shape->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET)->setBulletChar('•'); + +$shape->createTextRun('You can provide data for the helpers in many different ways'); +$shape->createParagraph() + ->getAlignment() + ->setLevel(1) + ->setMarginLeft(150) + ->setIndent(-25); + +$shape->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET)->setBulletChar('◦'); +$shape->createTextRun('Manual user input'); +$shape->createParagraph()->createTextRun('File upload (e.g. excel, csv)'); +$shape->createParagraph()->createTextRun('Database upload (e.g. sqlite)'); +$shape->createParagraph()->createTextRun('Database connection to local or remote database'); +$shape->createParagraph()->createTextRun('External APIs'); +$shape->createParagraph()->createTextRun('Internal APIs (everything from the Orange Management backend)'); + +$shape = new File(); +$shape->setName('Company Logo') + ->setDescription('Company Logo') + ->setPath(__DIR__ . '/logo.png') + ->setHeight(50) + ->setOffsetX(880) + ->setOffsetY(650); +$oSlide4->addShape($shape); + +// end screen +$oSlide5 = $objPHPPresentation->createSlide(); +$oSlide5->setBackground($oBkgColor); + +$shape = new File(); +$shape->setName('Company Logo') + ->setDescription('Company Logo') + ->setPath(__DIR__ . '/logo.png') + ->setHeight(300) + ->setOffsetX(320) + ->setOffsetY(120); +$oSlide5->addShape($shape); + +$shape = $oSlide5->createRichTextShape() + ->setHeight(300) + ->setWidth(600) + ->setOffsetX(180) + ->setOffsetY(450); +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); +$textRun = $shape->createTextRun('Thank You!'); +$textRun->getFont()->setBold(true)->setSize(42)->setColor($colorBlue); + +$writer = IOFactory::createWriter($objPHPPresentation, 'PowerPoint2007'); +$writer->save('php://output'); diff --git a/tests/depreciation/view.tpl.php b/tests/depreciation/view.tpl.php new file mode 100644 index 0000000..c87a77f --- /dev/null +++ b/tests/depreciation/view.tpl.php @@ -0,0 +1,58 @@ +getData('tcoll'); +$rcoll = $this->getData('rcoll'); +$cLang = $this->getData('lang'); +$template = $this->getData('template'); +$report = $this->getData('report'); +$basepath = \rtrim($this->getData('basepath') ?? '', '/'); + +/** @noinspection PhpIncludeInspection */ +$reportLanguage = include $basepath . '/' . \ltrim($tcoll['lang']->getPath(), '/'); +$lang = $reportLanguage[$cLang]; + +$amount = (float) ($this->request->getData('amount') ?? 10000.0); +$duration = (int) ($this->request->getData('duration') ?? 10); + +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
getCurrency(Depreciation::getStraightLineResidualInT($amount, $duration, $i), 'medium', ''); ?>getCurrency(Depreciation::getArithmeticDegressiveDepreciationResidualInT($amount, 0.0, $duration, $i), 'medium', ''); ?>getCurrency(Depreciation::getArithmeticProgressiveDepreciationResidualInT($amount, 0.0, $duration, $i), 'medium', ''); ?>getCurrency(Depreciation::getGeometicProgressiveDepreciationResidualInT($amount, $amount * 0.1, $duration, $i), 'medium', ''); ?>getCurrency(Depreciation::getGeometicDegressiveDepreciationResidualInT($amount, $amount * 0.1, $duration, $i), 'medium', ''); ?>
+ +
diff --git a/tests/depreciation/view.xls.php b/tests/depreciation/view.xls.php new file mode 100644 index 0000000..0b73dcb --- /dev/null +++ b/tests/depreciation/view.xls.php @@ -0,0 +1,56 @@ +getData('tcoll'); +$rcoll = $this->getData('rcoll'); +$cLang = $this->getData('lang'); +$template = $this->getData('template'); +$report = $this->getData('report'); +$basepath = \rtrim($this->getData('basepath') ?? '', '/'); + +/** @noinspection PhpIncludeInspection */ +$reportLanguage = include $basepath . '/' . \ltrim($tcoll['lang']->getPath(), '/'); +$lang = $reportLanguage[$cLang]; + +$amount = (float) ($this->request->getData('amount') ?? 10000.0); +$duration = (int) ($this->request->getData('duration') ?? 10); + +$spreadsheet = new Spreadsheet(); + +$spreadsheet->getProperties()->setCreator('Orange Management') + ->setLastModifiedBy('Orange Management') + ->setTitle('Orange Management - Depreciation Demo') + ->setSubject('Orange Management - Depreciation Demo') + ->setDescription('Demo') + ->setKeywords('demo helper depreciation') + ->setCategory('demo'); + +$spreadsheet->setActiveSheetIndex(0) + ->setCellValue('A1', $lang['Period']) + ->setCellValue('B1', $lang['StraightLine']) + ->setCellValue('C1', $lang['ArithmeticDegressive']) + ->setCellValue('D1', $lang['ArithmeticProgressive']) + ->setCellValue('E1', $lang['GeometricDegressive']) + ->setCellValue('F1', $lang['GeometricProgressive']); + +for ($i = 1; $i <= $duration; ++$i) { + $spreadsheet->setActiveSheetIndex(0) + ->setCellValue('A' . ($i + 1), $i) + ->setCellValue('B' . ($i + 1), $this->getCurrency(Depreciation::getStraightLineResidualInT($amount, $duration, $i), 'medium', '')) + ->setCellValue('C' . ($i + 1), $this->getCurrency(Depreciation::getArithmeticDegressiveDepreciationResidualInT($amount, 0.0, $duration, $i), 'medium', '')) + ->setCellValue('D' . ($i + 1), $this->getCurrency(Depreciation::getArithmeticProgressiveDepreciationResidualInT($amount, 0.0, $duration, $i), 'medium', '')) + ->setCellValue('E' . ($i + 1), $this->getCurrency(Depreciation::getGeometicProgressiveDepreciationResidualInT($amount, $amount * 0.1, $duration, $i), 'medium', '')) + ->setCellValue('F' . ($i + 1), $this->getCurrency(Depreciation::getGeometicDegressiveDepreciationResidualInT($amount, $amount * 0.1, $duration, $i), 'medium', '')); +} + +$spreadsheet->getActiveSheet()->setTitle($lang['Depreciation']); +$spreadsheet->setActiveSheetIndex(0); + +$writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); +$writer->save('php://output');