From af101e25bc70df8b33428de186fb579f4800232f Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Thu, 15 Jun 2023 01:53:48 +0200 Subject: [PATCH] Continue implementation. --- Admin/Install/Navigation.install.json | 2 +- Admin/Install/amounttypes.json | 30 + Admin/Install/db.json | 299 +++++- Admin/Installer.php | 91 +- Controller/ApiController.php | 1016 +++++++++++++++++++++ Models/{Money.php => Amount.php} | 15 +- Models/{MoneyType.php => AmountGroup.php} | 18 +- Models/AmountGroupMapper.php | 88 ++ Models/AmountMapper.php | 61 ++ Models/AmountTypeL11nMapper.php | 69 ++ Models/AmountTypeMapper.php | 83 ++ Models/Investment.php | 31 +- Models/InvestmentMapper.php | 117 +++ Models/InvestmentObject.php | 15 +- Models/InvestmentObjectMapper.php | 114 +++ Models/PermissionCategory.php | 2 + info.json | 3 +- 17 files changed, 2007 insertions(+), 47 deletions(-) create mode 100644 Admin/Install/amounttypes.json create mode 100644 Controller/ApiController.php rename Models/{Money.php => Amount.php} (73%) rename Models/{MoneyType.php => AmountGroup.php} (61%) create mode 100644 Models/AmountGroupMapper.php create mode 100644 Models/AmountMapper.php create mode 100644 Models/AmountTypeL11nMapper.php create mode 100644 Models/AmountTypeMapper.php create mode 100644 Models/InvestmentMapper.php create mode 100644 Models/InvestmentObjectMapper.php diff --git a/Admin/Install/Navigation.install.json b/Admin/Install/Navigation.install.json index b8dad4a..d84b59e 100755 --- a/Admin/Install/Navigation.install.json +++ b/Admin/Install/Navigation.install.json @@ -36,7 +36,7 @@ "type": 2, "subtype": 1, "name": "PurchaseInquiries", - "uri": "{/base}/private/investment?{?}", + "uri": "{/prefix}/private/investment?{?}", "target": "self", "icon": null, "order": 10, diff --git a/Admin/Install/amounttypes.json b/Admin/Install/amounttypes.json new file mode 100644 index 0000000..8fbed54 --- /dev/null +++ b/Admin/Install/amounttypes.json @@ -0,0 +1,30 @@ +[ + { + "name": "earnings", + "l11n": { + "en": "Earnings", + "de": "Erlöse" + } + }, + { + "name": "costs", + "l11n": { + "en": "Costs", + "de": "Kosten" + } + }, + { + "name": "cashflow", + "l11n": { + "en": "Cashflow", + "de": "Cashflow" + } + }, + { + "name": "depreciation", + "l11n": { + "en": "Depreciation", + "de": "Abschreibung" + } + } +] \ No newline at end of file diff --git a/Admin/Install/db.json b/Admin/Install/db.json index 9d2c723..d8104dc 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -9,8 +9,8 @@ "primary": true, "autoincrement": true }, - "investmgmt_investment_title": { - "name": "investmgmt_investment_title", + "investmgmt_investment_name": { + "name": "investmgmt_investment_name", "type": "VARCHAR(255)", "null": false }, @@ -19,6 +19,16 @@ "type": "TEXT", "null": false }, + "investmgmt_investment_status": { + "name": "investmgmt_investment_status", + "type": "TINYINT", + "null": false + }, + "investmgmt_investment_depreciation_type": { + "name": "investmgmt_investment_depreciation_type", + "type": "TINYINT", + "null": false + }, "investmgmt_investment_created_by": { "name": "investmgmt_investment_created_by", "type": "INT", @@ -33,60 +43,303 @@ "null": true, "foreignTable": "unit", "foreignKey": "unit_id" + }, + "investmgmt_investment_performance": { + "name": "investmgmt_investment_performance", + "type": "DATETIME", + "null": false + }, + "investmgmt_investment_created_at": { + "name": "investmgmt_investment_created_at", + "type": "DATETIME", + "null": false } } }, - "investmgmt_investment_option": { - "name": "investmgmt_investment_option", + "investmgmt_investmen_media": { + "name": "investmgmt_investmen_media", "fields": { - "investmgmt_investment_option_id": { - "name": "investmgmt_investment_option_id", + "investmgmt_investmen_media_id": { + "name": "investmgmt_investmen_media_id", "type": "INT", "null": false, "primary": true, "autoincrement": true }, - "investmgmt_investment_option_description": { - "name": "investmgmt_investment_option_description", + "investmgmt_investmen_media_investment": { + "name": "investmgmt_investmen_media_investment", + "type": "INT", + "null": false, + "foreignTable": "investmgmt_investmen", + "foreignKey": "investmgmt_investmen_id" + }, + "investmgmt_investmen_media_media": { + "name": "investmgmt_investmen_media_media", + "type": "INT", + "null": false, + "foreignTable": "media", + "foreignKey": "media_id" + } + } + }, + "investmgmt_investmen_note": { + "name": "investmgmt_investmen_note", + "fields": { + "investmgmt_investmen_note_id": { + "name": "investmgmt_investmen_note_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "investmgmt_investmen_note_investment": { + "name": "investmgmt_investmen_note_investment", + "type": "INT", + "null": false, + "foreignTable": "investmgmt_investmen", + "foreignKey": "investmgmt_investmen_id" + }, + "investmgmt_investmen_note_doc": { + "name": "investmgmt_investmen_note_doc", + "type": "INT", + "null": false, + "foreignTable": "editor_doc", + "foreignKey": "editor_doc_id" + } + } + }, + "investmgmt_option": { + "name": "investmgmt_option", + "fields": { + "investmgmt_option_id": { + "name": "investmgmt_option_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "investmgmt_option_name": { + "name": "investmgmt_option_name", + "type": "VARCHAR(255)", + "null": false + }, + "investmgmt_option_description": { + "name": "investmgmt_option_description", "type": "TEXT", "null": false }, - "investmgmt_investment_option_price": { - "name": "investmgmt_investment_option_price", - "type": "BIGINT", + "investmgmt_option_link": { + "name": "investmgmt_option_link", + "type": "TEXT", "null": false }, - "investmgmt_investment_option_investment": { - "name": "investmgmt_investment_option_investment", + "investmgmt_option_approved": { + "name": "investmgmt_option_approved", + "type": "TINYINT", + "null": false + }, + "investmgmt_option_investment": { + "name": "investmgmt_option_investment", "type": "INT", "null": false, "foreignTable": "investmgmt_investment", "foreignKey": "investmgmt_investment_id" }, - "investmgmt_investment_option_supplier": { - "name": "investmgmt_investment_option_supplier", + "investmgmt_option_supplier": { + "name": "investmgmt_option_supplier", "type": "INT", - "null": false, + "null": true, + "default": null, "foreignTable": "suppliermgmt_supplier", "foreignKey": "suppliermgmt_supplier_id" }, - "investmgmt_investment_option_supplier_alt": { - "name": "investmgmt_investment_option_supplier_alt", + "investmgmt_option_supplier_alt": { + "name": "investmgmt_option_supplier_alt", "type": "VARCHAR(255)", "null": false }, - "investmgmt_investment_option_item": { - "name": "investmgmt_investment_option_item", + "investmgmt_option_item": { + "name": "investmgmt_option_item", "type": "INT", - "null": false, + "null": true, + "default": null, "foreignTable": "itemmgmt_item", "foreignKey": "itemmgmt_item_id" }, - "investmgmt_investment_option_item_alt": { - "name": "investmgmt_investment_option_item_alt", + "investmgmt_option_parent": { + "name": "investmgmt_option_parent", + "type": "INT", + "null": true, + "default": null, + "foreignTable": "investmgmt_option", + "foreignKey": "investmgmt_option_id" + }, + } + }, + "investmgmt_option_media": { + "name": "investmgmt_option_media", + "fields": { + "investmgmt_option_media_id": { + "name": "investmgmt_option_media_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "investmgmt_option_media_option": { + "name": "investmgmt_option_media_option", + "type": "INT", + "null": false, + "foreignTable": "investmgmt_investmen", + "foreignKey": "investmgmt_option_id" + }, + "investmgmt_option_media_media": { + "name": "investmgmt_option_media_media", + "type": "INT", + "null": false, + "foreignTable": "media", + "foreignKey": "media_id" + } + } + }, + "investmgmt_option_note": { + "name": "investmgmt_option_note", + "fields": { + "investmgmt_option_note_id": { + "name": "investmgmt_option_note_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "investmgmt_option_note_option": { + "name": "investmgmt_option_note_option", + "type": "INT", + "null": false, + "foreignTable": "investmgmt_investmen", + "foreignKey": "investmgmt_option_id" + }, + "investmgmt_option_note_doc": { + "name": "investmgmt_option_note_doc", + "type": "INT", + "null": false, + "foreignTable": "editor_doc", + "foreignKey": "editor_doc_id" + } + } + }, + "investmgmt_amount_type": { + "name": "investmgmt_amount_type", + "fields": { + "investmgmt_amount_type_id": { + "name": "investmgmt_amount_type_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "investmgmt_amount_type_name": { + "name": "investmgmt_amount_type_name", "type": "VARCHAR(255)", "null": false } } + }, + "investmgmt_amount_type_l11n": { + "name": "investmgmt_amount_type_l11n", + "fields": { + "investmgmt_amount_type_l11n_id": { + "name": "investmgmt_amount_type_l11n_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "investmgmt_amount_type_l11n_title": { + "name": "investmgmt_amount_type_l11n_title", + "type": "VARCHAR(255)", + "null": false + }, + "investmgmt_amount_type_l11n_type": { + "name": "investmgmt_amount_type_l11n_type", + "type": "INT(11)", + "null": false, + "foreignTable": "investmgmt_amount_type", + "foreignKey": "investmgmt_amount_type_id" + }, + "investmgmt_amount_type_l11n_lang": { + "name": "investmgmt_amount_type_l11n_lang", + "type": "VARCHAR(2)", + "null": false, + "foreignTable": "language", + "foreignKey": "language_639_1" + } + } + }, + "investmgmt_amount_group": { + "name": "investmgmt_amount_group", + "fields": { + "investmgmt_amount_group_id": { + "name": "investmgmt_amount_group_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "investmgmt_amount_group_name": { + "name": "investmgmt_amount_group_name", + "type": "VARCHAR(255)", + "null": false + }, + "investmgmt_amount_group_type": { + "name": "investmgmt_amount_group_type", + "type": "INT(11)", + "null": false, + "foreignTable": "investmgmt_amount_type", + "foreignKey": "investmgmt_amount_type_id" + }, + "investmgmt_amount_group_option": { + "name": "investmgmt_amount_group_option", + "type": "INT(11)", + "null": false, + "foreignTable": "investmgmt_option", + "foreignKey": "investmgmt_option_id" + } + } + }, + "investmgmt_amount": { + "name": "investmgmt_amount", + "fields": { + "investmgmt_amount_id": { + "name": "investmgmt_amount_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "investmgmt_amount_name": { + "name": "investmgmt_amount_name", + "type": "VARCHAR(255)", + "null": false + }, + "investmgmt_amount_amount": { + "name": "investmgmt_amount_amount", + "type": "BIGINT", + "null": false + }, + "investmgmt_amount_date": { + "name": "investmgmt_amount_date", + "type": "DATETIME", + "null": true, + "default": null + }, + "investmgmt_amount_group": { + "name": "investmgmt_amount_group", + "type": "INT(11)", + "null": false, + "foreignTable": "investmgmt_amount_group", + "foreignKey": "investmgmt_amount_group_id" + } + } } } \ No newline at end of file diff --git a/Admin/Installer.php b/Admin/Installer.php index 7533ae5..d2c9b11 100755 --- a/Admin/Installer.php +++ b/Admin/Installer.php @@ -1,6 +1,6 @@ $amountTypes */ + $amountTypes = []; + + /** @var \Modules\InvestmentManagement\Controller\ApiController $module */ + $module = $app->moduleManager->getModuleInstance('InvestmentManagement', 'Api'); + + /** @var array $type */ + foreach ($types as $type) { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('name', $type['name'] ?? ''); + $request->setData('title', \reset($type['l11n'])); + $request->setData('language', \array_keys($type['l11n'])[0] ?? 'en'); + + $module->apiFuelTypeCreate($request, $response); + + $responseData = $response->get(''); + if (!\is_array($responseData)) { + continue; + } + + $amountTypes[$type['name']] = !\is_array($responseData['response']) + ? $responseData['response']->toArray() + : $responseData['response']; + + $isFirst = true; + foreach ($type['l11n'] as $language => $l11n) { + if ($isFirst) { + $isFirst = false; + continue; + } + + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('title', $l11n); + $request->setData('language', $language); + $request->setData('type', $amountTypes[$type['name']]['id']); + + $module->apiFuelTypeL11nCreate($request, $response); + } + } + + return $amountTypes; + } } diff --git a/Controller/ApiController.php b/Controller/ApiController.php new file mode 100644 index 0000000..86e00d5 --- /dev/null +++ b/Controller/ApiController.php @@ -0,0 +1,1016 @@ +validateInvestmentCreate($request))) { + $response->data[$request->uri->__toString()] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + /** @var Investment $investment */ + $investment = $this->createInvestmentFromRequest($request); + $this->createModel($request->header->account, $investment, InvestmentMapper::class, 'investment', $request->getOrigin()); + + if (!empty($request->files) + || !empty($request->getDataJson('media')) + ) { + $this->createInvestmentMedia($investment, $request); + } + + $this->fillJsonResponse( + $request, + $response, + NotificationLevel::OK, + '', + $this->app->l11nManager->getText($response->header->l11n->language, '0', '0', 'SucessfulCreate'), + $investment + ); + } + + /** + * Method to create investment from request. + * + * @param RequestAbstract $request Request + * + * @return Investment Returns the created investment from the request + * + * @since 1.0.0 + */ + public function createInvestmentFromRequest(RequestAbstract $request) : Investment + { + $investment = new Investment(); + $investment->name = $request->getDataString('name') ?? ''; + $investment->description = $request->getDataString('description') ?? ''; + $investment->unit = $request->getDataInt('unit') ?? $this->app->unitId; + $investment->createdBy = new NullAccount($request->header->account); + + return $investment; + } + + /** + * Create media files for investment + * + * @param Investment $investment Investment + * @param RequestAbstract $request Request incl. media do upload + * + * @return void + * + * @since 1.0.0 + */ + private function createInvestmentMedia(Investment $investment, RequestAbstract $request) : void + { + $path = $this->createInvestmentDir($investment); + + if (!empty($uploadedFiles = $request->files)) { + $uploaded = $this->app->moduleManager->get('Media')->uploadFiles( + names: [], + fileNames: [], + files: $uploadedFiles, + account: $request->header->account, + basePath: __DIR__ . '/../../../Modules/Media/Files' . $path, + virtualPath: $path, + pathSettings: PathSettings::FILE_PATH + ); + + $collection = null; + foreach ($uploaded as $media) { + $this->createModelRelation( + $request->header->account, + $investment->id, + $media->id, + InvestmentMapper::class, + 'files', + '', + $request->getOrigin() + ); + + if ($collection === null) { + /** @var \Modules\Media\Models\Collection $collection */ + $collection = MediaMapper::getParentCollection($path)->limit(1)->execute(); + + if ($collection->id === 0) { + $collection = $this->app->moduleManager->get('Media')->createRecursiveMediaCollection( + $path, + $request->header->account, + __DIR__ . '/../../../Modules/Media/Files' . $path + ); + } + } + + $this->createModelRelation( + $request->header->account, + $collection->id, + $media->id, + CollectionMapper::class, + 'sources', + '', + $request->getOrigin() + ); + } + } + + if (!empty($mediaFiles = $request->getDataJson('media'))) { + $collection = null; + + foreach ($mediaFiles as $file) { + /** @var \Modules\Media\Models\Media $media */ + $media = MediaMapper::get()->where('id', (int) $file)->limit(1)->execute(); + + $this->createModelRelation( + $request->header->account, + $investment->id, + $media->id, + InvestmentMapper::class, + 'files', + '', + $request->getOrigin() + ); + + $ref = new Reference(); + $ref->name = $media->name; + $ref->source = new NullMedia($media->id); + $ref->createdBy = new NullAccount($request->header->account); + $ref->setVirtualPath($path); + + $this->createModel($request->header->account, $ref, ReferenceMapper::class, 'media_reference', $request->getOrigin()); + + if ($collection === null) { + /** @var \Modules\Media\Models\Collection $collection */ + $collection = MediaMapper::getParentCollection($path)->limit(1)->execute(); + + if ($collection->id === 0) { + $collection = $this->app->moduleManager->get('Media')->createRecursiveMediaCollection( + $path, + $request->header->account, + __DIR__ . '/../../../Modules/Media/Files' . $path + ); + } + } + + $this->createModelRelation( + $request->header->account, + $collection->id, + $ref->id, + CollectionMapper::class, + 'sources', + '', + $request->getOrigin() + ); + } + } + } + + /** + * Api method to create a bill + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiMediaAddToInvestment(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + if (!empty($val = $this->validateMediaAddToInvestment($request))) { + $response->data[$request->uri->__toString()] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + /** @var \Modules\FleetManagement\Models\Investment $investment */ + $investment = InvestmentMapper::get()->where('id', (int) $request->getData('investment'))->execute(); + $path = $this->createInvestmentDir($investment); + + $uploaded = []; + if (!empty($uploadedFiles = $request->files)) { + $uploaded = $this->app->moduleManager->get('Media')->uploadFiles( + names: [], + fileNames: [], + files: $uploadedFiles, + account: $request->header->account, + basePath: __DIR__ . '/../../../Modules/Media/Files' . $path, + virtualPath: $path, + pathSettings: PathSettings::FILE_PATH, + hasAccountRelation: false, + readContent: (bool) ($request->getData('parse_content') ?? false) + ); + + $collection = null; + foreach ($uploaded as $media) { + $this->createModelRelation( + $request->header->account, + $investment->id, + $media->id, + InvestmentMapper::class, + 'files', + '', + $request->getOrigin() + ); + + if ($request->hasData('type')) { + $this->createModelRelation( + $request->header->account, + $media->id, + $request->getDataInt('type'), + MediaMapper::class, + 'types', + '', + $request->getOrigin() + ); + } + + if ($collection === null) { + /** @var \Modules\Media\Models\Collection $collection */ + $collection = MediaMapper::getParentCollection($path)->limit(1)->execute(); + + if ($collection->id === 0) { + $collection = $this->app->moduleManager->get('Media')->createRecursiveMediaCollection( + $path, + $request->header->account, + __DIR__ . '/../../../Modules/Media/Files' . $path, + ); + } + } + + $this->createModelRelation( + $request->header->account, + $collection->id, + $media->id, + CollectionMapper::class, + 'sources', + '', + $request->getOrigin() + ); + } + } + + if (!empty($mediaFiles = $request->getDataJson('media'))) { + foreach ($mediaFiles as $media) { + $this->createModelRelation( + $request->header->account, + $investment->id, + (int) $media, + InvestmentMapper::class, + 'files', + '', + $request->getOrigin() + ); + } + } + + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Media', 'Media added to investment.', [ + 'upload' => $uploaded, + 'media' => $mediaFiles, + ]); + } + + /** + * Method to validate bill creation from request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateMediaAddToInvestment(RequestAbstract $request) : array + { + $val = []; + if (($val['media'] = (!$request->hasData('media') && empty($request->files))) + || ($val['investment'] = !$request->hasData('investment')) + ) { + return $val; + } + + return []; + } + + /** + * Validate investment create request + * + * @param RequestAbstract $request Request + * + * @return array Returns the validation array of the request + * + * @since 1.0.0 + */ + private function validateInvestmentCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['name'] = !$request->hasData('name')) + ) { + return $val; + } + + return []; + } + + /** + * Create media directory path + * + * @param Investment $investment Investment + * + * @return string + * + * @since 1.0.0 + */ + private function createInvestmentDir(Investment $investment) : string + { + return '/Modules/InvestmentManagement/Investment/' + . $this->app->unitId . '/' + . $investment->id; + } + + /** + * Create media directory path + * + * @param Investment $investment Investment + * + * @return string + * + * @since 1.0.0 + */ + private function createInvestmentObjectDir(InvestmentObject $object) : string + { + return '/Modules/InvestmentManagement/Investment/' + . $this->app->unitId . '/' + . $object->investment; + } + + /** + * Api method to create a investment + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiInvestmentOptionCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + if (!empty($val = $this->validateInvestmentOptionCreate($request))) { + $response->data[$request->uri->__toString()] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + /** @var InvestmentOption $investment */ + $investment = $this->createInvestmentOptionFromRequest($request); + $this->createModel($request->header->account, $investment, InvestmentObjectMapper::class, 'investment_option', $request->getOrigin()); + + if (!empty($request->files) + || !empty($request->getDataJson('media')) + ) { + $this->createInvestmentObjectMedia($investment, $request); + } + + $this->fillJsonResponse( + $request, + $response, + NotificationLevel::OK, + '', + $this->app->l11nManager->getText($response->header->l11n->language, '0', '0', 'SucessfulCreate'), + $investment + ); + } + + /** + * Validate investment create request + * + * @param RequestAbstract $request Request + * + * @return array Returns the validation array of the request + * + * @since 1.0.0 + */ + private function validateInvestmentOptionCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['name'] = !$request->hasData('name')) + || ($val['investment'] = !$request->hasData('investment')) + ) { + return $val; + } + + return []; + } + + /** + * Method to create investment from request. + * + * @param RequestAbstract $request Request + * + * @return InvestmentObject Returns the created investment from the request + * + * @since 1.0.0 + */ + public function createInvestmentOptionFromRequest(RequestAbstract $request) : InvestmentObject + { + $investment = new InvestmentObject(); + $investment->name = $request->getDataString('name') ?? ''; + $investment->description = $request->getDataString('description') ?? ''; + $investment->link = $request->getDataString('link') ?? ''; + $investment->investment = (int) $request->getData('investment'); + $investment->parent = $request->getDataInt('parent'); + $investment->supplier = $request->getDataInt('supplier') ?? 0; + $investment->supplierName = $request->getDataString('supplierName') ?? ''; + $investment->item = $request->getDataInt('item'); + $investment->performanceDate = $request->getDataDateTime('performance') ?? $investment->createdAt; + + // @todo: reconsider the following lines. This seems rather complicated. + if ($request->hasData('amount')) { + $types = AmountTypeMapper::getAll()->execute(); + + foreach ($types as $type) { + if ($type->title = 'costs') { + $defaultGroup = new AmountGroup(); + $defaultGroup->name = 'Purchase Price'; // @todo: replace with api l11n + $defaultGroup->type = $type->id; + + $amount = new Amount(); + $amount->amount = new FloatInt((int) $request->getDataInt('amount')); + + $defaultGroup->amounts[] = $amount; + + $investment->amountGroups[] = $defaultGroup; + } elseif ($type->title === 'cashflow') { + $defaultGroup = new AmountGroup(); + $defaultGroup->name = 'Cashflow'; // @todo: replace with api l11n + $defaultGroup->type = $type->id; + + // @todo: calculate date based on performance date + offer conditions / 30 days + $amount = new Amount(); + $amount->amount = new FloatInt((int) $request->getDataInt('amount')); + + $defaultGroup->amounts[] = $amount; + + $investment->amountGroups[] = $defaultGroup; + } elseif ($type->title === 'depreciation') { + $defaultGroup = new AmountGroup(); + $defaultGroup->name = 'Depreciation'; // @todo: replace with api l11n + $defaultGroup->type = $type->id; + + // @todo: calculate automatic depreciation; + $amount = new Amount(); + $amount->amount = new FloatInt((int) $request->getDataInt('amount')); + + $defaultGroup->amounts[] = $amount; + + $investment->amountGroups[] = $defaultGroup; + } + } + } + + return $investment; + } + + /** + * Api method to create a investment + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiAmountTypeCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + if (!empty($val = $this->validateAmountTypeCreate($request))) { + $response->data[$request->uri->__toString()] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + /** @var BaseStringL11nType $amount */ + $amount = $this->createAmountTypeFromRequest($request); + $this->createModel($request->header->account, $amount, AmountTypeMapper::class, 'amount_type', $request->getOrigin()); + + $this->fillJsonResponse( + $request, + $response, + NotificationLevel::OK, + '', + $this->app->l11nManager->getText($response->header->l11n->language, '0', '0', 'SucessfulCreate'), + $amount + ); + } + + /** + * Create media files for investment + * + * @param InvestmentObject $investment Investment + * @param RequestAbstract $request Request incl. media do upload + * + * @return void + * + * @since 1.0.0 + */ + private function createInvestmentObjectMedia(InvestmentObject $investment, RequestAbstract $request) : void + { + $path = $this->createInvestmentObjectDir($investment); + + if (!empty($uploadedFiles = $request->files)) { + $uploaded = $this->app->moduleManager->get('Media')->uploadFiles( + names: [], + fileNames: [], + files: $uploadedFiles, + account: $request->header->account, + basePath: __DIR__ . '/../../../Modules/Media/Files' . $path, + virtualPath: $path, + pathSettings: PathSettings::FILE_PATH + ); + + $collection = null; + foreach ($uploaded as $media) { + $this->createModelRelation( + $request->header->account, + $investment->id, + $media->id, + InvestmentObjectMapper::class, + 'files', + '', + $request->getOrigin() + ); + + if ($collection === null) { + /** @var \Modules\Media\Models\Collection $collection */ + $collection = MediaMapper::getParentCollection($path)->limit(1)->execute(); + + if ($collection->id === 0) { + $collection = $this->app->moduleManager->get('Media')->createRecursiveMediaCollection( + $path, + $request->header->account, + __DIR__ . '/../../../Modules/Media/Files' . $path + ); + } + } + + $this->createModelRelation( + $request->header->account, + $collection->id, + $media->id, + CollectionMapper::class, + 'sources', + '', + $request->getOrigin() + ); + } + } + + if (!empty($mediaFiles = $request->getDataJson('media'))) { + $collection = null; + + foreach ($mediaFiles as $file) { + /** @var \Modules\Media\Models\Media $media */ + $media = MediaMapper::get()->where('id', (int) $file)->limit(1)->execute(); + + $this->createModelRelation( + $request->header->account, + $investment->id, + $media->id, + InvestmentObjectMapper::class, + 'files', + '', + $request->getOrigin() + ); + + $ref = new Reference(); + $ref->name = $media->name; + $ref->source = new NullMedia($media->id); + $ref->createdBy = new NullAccount($request->header->account); + $ref->setVirtualPath($path); + + $this->createModel($request->header->account, $ref, ReferenceMapper::class, 'media_reference', $request->getOrigin()); + + if ($collection === null) { + /** @var \Modules\Media\Models\Collection $collection */ + $collection = MediaMapper::getParentCollection($path)->limit(1)->execute(); + + if ($collection->id === 0) { + $collection = $this->app->moduleManager->get('Media')->createRecursiveMediaCollection( + $path, + $request->header->account, + __DIR__ . '/../../../Modules/Media/Files' . $path + ); + } + } + + $this->createModelRelation( + $request->header->account, + $collection->id, + $ref->id, + CollectionMapper::class, + 'sources', + '', + $request->getOrigin() + ); + } + } + } + + /** + * Api method to create a bill + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiMediaAddToInvestmentObject(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + if (!empty($val = $this->validateMediaAddToInvestment($request))) { + $response->data[$request->uri->__toString()] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + /** @var \Modules\FleetManagement\Models\InvestmentObject $investment */ + $investment = InvestmentObjectMapper::get()->where('id', (int) $request->getData('option'))->execute(); + $path = $this->createInvestmentObjectDir($investment); + + $uploaded = []; + if (!empty($uploadedFiles = $request->files)) { + $uploaded = $this->app->moduleManager->get('Media')->uploadFiles( + names: [], + fileNames: [], + files: $uploadedFiles, + account: $request->header->account, + basePath: __DIR__ . '/../../../Modules/Media/Files' . $path, + virtualPath: $path, + pathSettings: PathSettings::FILE_PATH, + hasAccountRelation: false, + readContent: (bool) ($request->getData('parse_content') ?? false) + ); + + $collection = null; + foreach ($uploaded as $media) { + $this->createModelRelation( + $request->header->account, + $investment->id, + $media->id, + InvestmentObjectMapper::class, + 'files', + '', + $request->getOrigin() + ); + + if ($request->hasData('type')) { + $this->createModelRelation( + $request->header->account, + $media->id, + $request->getDataInt('type'), + MediaMapper::class, + 'types', + '', + $request->getOrigin() + ); + } + + if ($collection === null) { + /** @var \Modules\Media\Models\Collection $collection */ + $collection = MediaMapper::getParentCollection($path)->limit(1)->execute(); + + if ($collection->id === 0) { + $collection = $this->app->moduleManager->get('Media')->createRecursiveMediaCollection( + $path, + $request->header->account, + __DIR__ . '/../../../Modules/Media/Files' . $path, + ); + } + } + + $this->createModelRelation( + $request->header->account, + $collection->id, + $media->id, + CollectionMapper::class, + 'sources', + '', + $request->getOrigin() + ); + } + } + + if (!empty($mediaFiles = $request->getDataJson('media'))) { + foreach ($mediaFiles as $media) { + $this->createModelRelation( + $request->header->account, + $investment->id, + (int) $media, + InvestmentObjectMapper::class, + 'files', + '', + $request->getOrigin() + ); + } + } + + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Media', 'Media added to investment.', [ + 'upload' => $uploaded, + 'media' => $mediaFiles, + ]); + } + + /** + * Method to validate bill creation from request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateMediaAddToInvestment(RequestAbstract $request) : array + { + $val = []; + if (($val['media'] = (!$request->hasData('media') && empty($request->files))) + || ($val['investment'] = !$request->hasData('investment')) + ) { + return $val; + } + + return []; + } + + /** + * Method to create investment from request. + * + * @param RequestAbstract $request Request + * + * @return BaseStringL11nType Returns the created investment from the request + * + * @since 1.0.0 + */ + public function createAmountTypeFromRequest(RequestAbstract $request) : BaseStringL11nType + { + $type = new BaseStringL11nType(); + $type->title = $request->getDataString('name') ?? ''; + $type->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN); + + return $type; + } + + /** + * Validate investment create request + * + * @param RequestAbstract $request Request + * + * @return array Returns the validation array of the request + * + * @since 1.0.0 + */ + private function validateAmountTypeCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['name'] = !$request->hasData('name')) + || ($val['title'] = !$request->hasData('title')) + ) { + return $val; + } + + return []; + } + + /** + * Api method to create investment attribute l11n + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiAmountTypeL11nCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + if (!empty($val = $this->validateAmountTypeL11nCreate($request))) { + $response->data['amount_type_l11n_create'] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + $typeL11n = $this->createAmountTypeL11nFromRequest($request); + $this->createModel($request->header->account, $typeL11n, AmountTypeL11nMapper::class, 'amount_type_l11n', $request->getOrigin()); + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Localization', 'Localization successfully created', $typeL11n); + } + + /** + * Method to create investment attribute l11n from request. + * + * @param RequestAbstract $request Request + * + * @return BaseStringL11n + * + * @since 1.0.0 + */ + private function createAmountTypeL11nFromRequest(RequestAbstract $request) : BaseStringL11n + { + $typeL11n = new BaseStringL11n(); + $typeL11n->ref = $request->getDataInt('type') ?? 0; + $typeL11n->setLanguage( + $request->getDataString('language') ?? $request->header->l11n->language + ); + $typeL11n->content = $request->getDataString('title') ?? ''; + + return $typeL11n; + } + + /** + * Validate investment attribute l11n create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateAmountTypeL11nCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['title'] = !$request->hasData('title')) + || ($val['type'] = !$request->hasData('type')) + ) { + return $val; + } + + return []; + } + + /** + * Api method to create notes + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiNoteCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + if (!empty($val = $this->validateNoteCreate($request))) { + $response->data['investment_note_create'] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + $request->setData('virtualpath', '/Modules/FleetManagement/Investment/' . $request->getData('id'), true); + $this->app->moduleManager->get('Editor', 'Api')->apiEditorCreate($request, $response, $data); + + if ($response->header->status !== RequestStatusCode::R_200) { + return; + } + + $responseData = $response->get($request->uri->__toString()); + if (!\is_array($responseData)) { + return; + } + + $model = $responseData['response']; + $this->createModelRelation($request->header->account, (int) $request->getData('id'), $model->id, InvestmentMapper::class, 'notes', '', $request->getOrigin()); + } + + /** + * Validate item note create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateNoteCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['id'] = !$request->hasData('id')) + ) { + return $val; + } + + return []; + } + + /** + * Api method to update note + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiNoteEdit(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + $this->app->moduleManager->get('Editor', 'Api')->apiEditorUpdate($request, $response, $data); + + if ($response->header->status !== RequestStatusCode::R_200) { + return; + } + + $responseData = $response->get($request->uri->__toString()); + if (!\is_array($responseData)) { + return; + } + } +} diff --git a/Models/Money.php b/Models/Amount.php similarity index 73% rename from Models/Money.php rename to Models/Amount.php index 0587146..db3e849 100644 --- a/Models/Money.php +++ b/Models/Amount.php @@ -25,21 +25,20 @@ use phpOMS\Stdlib\Base\FloatInt; * @link https://orange-management.org * @since 1.0.0 */ -class Money +class Amount { public int $id = 0; public string $name = ''; - public int $depreciationType = DepreciationType::STAIGHT_LINE; - - public int $depreciationDuration = 0; - public FloatInt $amount; - public FloatInt $residualValue; + public int $group = 0; - public MoneyType $moneyType; + public ?\DateTime $date = null; - public bool $recurring = false; + public function __construct() + { + $this->amount = new FloatInt(); + } } diff --git a/Models/MoneyType.php b/Models/AmountGroup.php similarity index 61% rename from Models/MoneyType.php rename to Models/AmountGroup.php index 733d02d..fa2a612 100644 --- a/Models/MoneyType.php +++ b/Models/AmountGroup.php @@ -14,25 +14,31 @@ declare(strict_types=1); namespace Modules\InvestmentManagement\Models; -use phpOMS\Localization\BaseStringL11n; +use phpOMS\Business\Finance\DepreciationType; +use phpOMS\Stdlib\Base\FloatInt; /** - * Money type (one off cost, recurring, earnings). + * Costs/Earnings. * * @package Modules\InvestmentManagement\Models * @license OMS License 2.0 * @link https://orange-management.org * @since 1.0.0 */ -class MoneyType +class AmountGroup { public int $id = 0; public string $name = ''; - public BaseStringL11n $content; + public array $amounts = []; - public bool $cost = true; + public BaseStringL11nType $type; - public bool $recurring = false; + public int $option = 0; + + public function __construct() + { + $this->type = new BaseStringL11nType(); + } } diff --git a/Models/AmountGroupMapper.php b/Models/AmountGroupMapper.php new file mode 100644 index 0000000..584c36b --- /dev/null +++ b/Models/AmountGroupMapper.php @@ -0,0 +1,88 @@ + + */ +final class AmountGroupMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'investmgmt_amount_group_id' => ['name' => 'investmgmt_amount_group_id', 'type' => 'int', 'internal' => 'id'], + 'investmgmt_amount_group_name' => ['name' => 'investmgmt_amount_group_name', 'type' => 'string', 'internal' => 'name'], + 'investmgmt_amount_group_type' => ['name' => 'investmgmt_amount_group_type', 'type' => 'int', 'internal' => 'type'], + 'investmgmt_amount_group_option' => ['name' => 'investmgmt_amount_group_option', 'type' => 'int', 'internal' => 'option'], + ]; + + /** + * Has one relation. + * + * @var array + * @since 1.0.0 + */ + public const OWNS_ONE = [ + 'type' => [ + 'mapper' => AmountTypeMapper::class, + 'external' => 'investmgmt_amount_group_type', + ], + ]; + + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + public const HAS_MANY = [ + 'amounts' => [ + 'mapper' => AmountGroupMapper::class, + 'table' => 'investmgmt_amount', + 'self' => 'investmgmt_amount_group', + 'external' => null, + ], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'investmgmt_amount_group'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'investmgmt_amount_group_id'; +} diff --git a/Models/AmountMapper.php b/Models/AmountMapper.php new file mode 100644 index 0000000..f398928 --- /dev/null +++ b/Models/AmountMapper.php @@ -0,0 +1,61 @@ + + */ +final class AmountGroupMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'investmgmt_amount_id' => ['name' => 'investmgmt_amount_id', 'type' => 'int', 'internal' => 'id'], + 'investmgmt_amount_name' => ['name' => 'investmgmt_amount_name', 'type' => 'string', 'internal' => 'name'], + 'investmgmt_amount_amount' => ['name' => 'investmgmt_amount_amount', 'type' => 'Serializable', 'internal' => 'type'], + 'investmgmt_amount_date' => ['name' => 'investmgmt_amount_date', 'type' => 'DateTime', 'internal' => 'date'], + 'investmgmt_amount_group' => ['name' => 'investmgmt_amount_group', 'type' => 'int', 'internal' => 'group'], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'investmgmt_amount'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'investmgmt_amount_id'; +} diff --git a/Models/AmountTypeL11nMapper.php b/Models/AmountTypeL11nMapper.php new file mode 100644 index 0000000..2675d70 --- /dev/null +++ b/Models/AmountTypeL11nMapper.php @@ -0,0 +1,69 @@ + + */ +final class AmountTypeL11nMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'investmgmt_amount_type_l11n_id' => ['name' => 'investmgmt_amount_type_l11n_id', 'type' => 'int', 'internal' => 'id'], + 'investmgmt_amount_type_l11n_title' => ['name' => 'investmgmt_amount_type_l11n_title', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true], + 'investmgmt_amount_type_l11n_type' => ['name' => 'investmgmt_amount_type_l11n_type', 'type' => 'int', 'internal' => 'ref'], + 'investmgmt_amount_type_l11n_lang' => ['name' => 'investmgmt_amount_type_l11n_lang', 'type' => 'string', 'internal' => 'language'], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'investmgmt_amount_type_l11n'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'investmgmt_amount_type_l11n_id'; + + /** + * Model to use by the mapper. + * + * @var class-string + * @since 1.0.0 + */ + public const MODEL = BaseStringL11n::class; +} diff --git a/Models/AmountTypeMapper.php b/Models/AmountTypeMapper.php new file mode 100644 index 0000000..a3a11e4 --- /dev/null +++ b/Models/AmountTypeMapper.php @@ -0,0 +1,83 @@ + + */ +final class AmountTypeMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'investmgmt_amount_type_id' => ['name' => 'investmgmt_amount_type_id', 'type' => 'int', 'internal' => 'id'], + 'investmgmt_amount_type_name' => ['name' => 'investmgmt_amount_type_name', 'type' => 'string', 'internal' => 'title', 'autocomplete' => true], + ]; + + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + public const HAS_MANY = [ + 'l11n' => [ + 'mapper' => AmountTypeL11nMapper::class, + 'table' => 'investmgmt_amount_type_l11n', + 'self' => 'investmgmt_amount_type_l11n_type', + 'column' => 'content', + 'external' => null, + ], + ]; + + /** + * Model to use by the mapper. + * + * @var class-string + * @since 1.0.0 + */ + public const MODEL = BaseStringL11nType::class; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'investmgmt_amount_type'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'investmgmt_amount_type_id'; +} diff --git a/Models/Investment.php b/Models/Investment.php index d0a585a..e7196c5 100644 --- a/Models/Investment.php +++ b/Models/Investment.php @@ -15,6 +15,7 @@ declare(strict_types=1); namespace Modules\InvestmentManagement\Models; use Modules\Admin\Models\Account; +use Modules\Admin\Models\NullAccount; use phpOMS\Business\Finance\DepreciationType; /** @@ -31,9 +32,13 @@ class Investment public string $name = ''; - public int $depreciationType = DepreciationType::STAIGHT_LINE; + public string $description = ''; - public array $objects = []; + public int $depreciationType = DepreciationType::NONE; + + public int $status = InvestmentStatus::DRAFT; + + public array $options = []; /** * Income @@ -42,5 +47,27 @@ class Investment public Account $createdBy; + public \DateTimeImmutable $createdAt; + + public \DateTime $performanceDate; + public array $attributeTypes = []; + + public ?int $unit = null; + + /** + * Constructor. + * + * @since 1.0.0 + */ + public __construct() + { + $this->createdBy = new NullAccount(); + $this->createdAt = new \DateTimeImmutable('now'); + $this->perforamnceDate = new \DateTime('now'); + } + + use \Modules\Media\Models\MediaListTrait; + use \Modules\Editor\Models\EditorDocListTrait; + use \Modules\Attribute\Models\AttributeHolderTrait; } diff --git a/Models/InvestmentMapper.php b/Models/InvestmentMapper.php new file mode 100644 index 0000000..1af628b --- /dev/null +++ b/Models/InvestmentMapper.php @@ -0,0 +1,117 @@ + + */ +final class InvestmentMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'investmgmt_investment_id' => ['name' => 'investmgmt_investment_id', 'type' => 'int', 'internal' => 'id'], + 'investmgmt_investment_name' => ['name' => 'investmgmt_investment_name', 'type' => 'string', 'internal' => 'name'], + 'investmgmt_investment_description' => ['name' => 'investmgmt_investment_description', 'type' => 'string', 'internal' => 'description'], + 'investmgmt_investment_status' => ['name' => 'investmgmt_investment_status', 'type' => 'int', 'internal' => 'status'], + 'investmgmt_investment_depreciation_type' => ['name' => 'investmgmt_investment_depreciation_type', 'type' => 'int', 'internal' => 'depreciationType'], + 'investmgmt_investment_unit' => ['name' => 'investmgmt_investment_unit', 'type' => 'int', 'internal' => 'unit'], + 'investmgmt_investment_created_by' => ['name' => 'investmgmt_investment_created_by', 'type' => 'int', 'internal' => 'createdBy', 'readonly' => true], + 'investmgmt_investment_performance' => ['name' => 'investmgmt_investment_performance', 'type' => 'DateTime', 'internal' => 'performanceDate'], + 'investmgmt_investment_created_at' => ['name' => 'investmgmt_investment_created_at', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt', 'readonly' => true], + ]; + + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + public const HAS_MANY = [ + 'files' => [ + 'mapper' => MediaMapper::class, /* mapper of the related object */ + 'table' => 'investmgmt_investment_media', /* table of the related object, null if no relation table is used (many->1) */ + 'external' => 'investmgmt_investment_media_media', + 'self' => 'investmgmt_investment_media_investment', + ], + 'notes' => [ + 'mapper' => EditorDocMapper::class, /* mapper of the related object */ + 'table' => 'investmgmt_investment_note', /* table of the related object, null if no relation table is used (many->1) */ + 'external' => 'investmgmt_investment_note_doc', + 'self' => 'investmgmt_investment_note_investment', + ], + 'options' => [ + 'mapper' => InvestmentObjectMapper::class, + 'table' => 'investmgmt_investment_option', + 'self' => 'investmgmt_investment_option_investment', + 'external' => null, + ], + ]; + + /** + * Belongs to. + * + * @var array + * @since 1.0.0 + */ + public const BELONGS_TO = [ + 'createdBy' => [ + 'mapper' => AccountMapper::class, + 'external' => 'investmgmt_investment_created_by', + ], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'investmgmt_investment'; + + /** + * Created at. + * + * @var string + * @since 1.0.0 + */ + public const CREATED_AT = 'investmgmt_investment_created_at'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'investmgmt_investment_id'; +} diff --git a/Models/InvestmentObject.php b/Models/InvestmentObject.php index bc0ba97..ec1deca 100644 --- a/Models/InvestmentObject.php +++ b/Models/InvestmentObject.php @@ -26,7 +26,7 @@ class InvestmentObject { public int $id = 0; - public string $productName = ''; + public string $name = ''; public string $description = ''; @@ -34,14 +34,23 @@ class InvestmentObject public string $supplierName = ''; - public string $productLink = ''; + public string $link = ''; /** * Costs / Revenue */ - public array $money = []; + public array $amountGroups = []; public bool $approved = false; public array $attributes = []; + + public ?int $parent = null; + + public int $investment = 0; + + public ?int $item = null; + + use \Modules\Media\Models\MediaListTrait; + use \Modules\Editor\Models\EditorDocListTrait; } diff --git a/Models/InvestmentObjectMapper.php b/Models/InvestmentObjectMapper.php new file mode 100644 index 0000000..4ce9604 --- /dev/null +++ b/Models/InvestmentObjectMapper.php @@ -0,0 +1,114 @@ + + */ +final class InvestmentObjectMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'investmgmt_option_id' => ['name' => 'investmgmt_option_id', 'type' => 'int', 'internal' => 'id'], + 'investmgmt_option_name' => ['name' => 'investmgmt_option_name', 'type' => 'string', 'internal' => 'name'], + 'investmgmt_option_description' => ['name' => 'investmgmt_option_description', 'type' => 'string', 'internal' => 'description'], + 'investmgmt_option_link' => ['name' => 'investmgmt_option_link', 'type' => 'string', 'internal' => 'link'], + 'investmgmt_option_supplier' => ['name' => 'investmgmt_option_supplier', 'type' => 'int', 'internal' => 'supplier'], + 'investmgmt_option_supplier_alt' => ['name' => 'investmgmt_option_supplier_alt', 'type' => 'string', 'internal' => 'supplierName'], + 'investmgmt_option_item' => ['name' => 'investmgmt_option_item', 'type' => 'int', 'internal' => 'item'], + 'investmgmt_option_approved' => ['name' => 'investmgmt_option_approved', 'type' => 'bool', 'internal' => 'approved'], + 'investmgmt_option_investment' => ['name' => 'investmgmt_option_investment', 'type' => 'int', 'internal' => 'investment'], + ]; + + /** + * Has one relation. + * + * @var array + * @since 1.0.0 + */ + public const OWNS_ONE = [ + 'supplier' => [ + 'mapper' => SupplierMapper::class, + 'external' => 'investmgmt_option_supplier', + ], + 'item' => [ + 'mapper' => ItemMapper::class, + 'external' => 'investmgmt_option_item', + ], + ]; + + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + public const HAS_MANY = [ + 'files' => [ + 'mapper' => MediaMapper::class, /* mapper of the related object */ + 'table' => 'investmgmt_option_media', /* table of the related object, null if no relation table is used (many->1) */ + 'external' => 'investmgmt_option_media_media', + 'self' => 'investmgmt_option_media_option', + ], + 'notes' => [ + 'mapper' => EditorDocMapper::class, /* mapper of the related object */ + 'table' => 'investmgmt_option_note', /* table of the related object, null if no relation table is used (many->1) */ + 'external' => 'investmgmt_option_note_doc', + 'self' => 'investmgmt_option_note_option', + ], + 'amountGroups' => [ + 'mapper' => AmountGroupMapper::class, + 'table' => 'investmgmt_amount_group', + 'self' => 'investmgmt_amount_group_option', + 'external' => null, + ], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'investmgmt_option'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'investmgmt_option_id'; +} diff --git a/Models/PermissionCategory.php b/Models/PermissionCategory.php index 17612ea..22f0294 100755 --- a/Models/PermissionCategory.php +++ b/Models/PermissionCategory.php @@ -27,4 +27,6 @@ use phpOMS\Stdlib\Base\Enum; abstract class PermissionCategory extends Enum { public const INVESTMENT = 1; + + public const AMOUNT_TYPE = 1; } diff --git a/info.json b/info.json index 6f07d86..25861ba 100755 --- a/info.json +++ b/info.json @@ -18,7 +18,8 @@ "directory": "InvestmentManagement", "dependencies": { "Finance": "*", - "SupplierManagement": "*" + "SupplierManagement": "*", + "ItemManagement": "*" }, "providing": { "Navigation": "*"