diff --git a/Admin/Install/Navigation.install.json b/Admin/Install/Navigation.install.json index 4cc55c3..65944ab 100755 --- a/Admin/Install/Navigation.install.json +++ b/Admin/Install/Navigation.install.json @@ -8,7 +8,7 @@ "uri": "{/base}/finance/loan/list?{?}", "target": "self", "icon": null, - "order": 1, + "order": 10, "from": "LoanManagement", "permission": { "permission": 2, "type": null, "element": null }, "parent": 1008101001, @@ -33,8 +33,8 @@ "pid": "/finance/loan", "type": 3, "subtype": 1, - "name": "Table", - "uri": "{/base}/finance/loan/table?{?}", + "name": "Create", + "uri": "{/base}/finance/loan/create?{?}", "target": "self", "icon": null, "order": 5, @@ -48,7 +48,22 @@ "pid": "/finance/loan", "type": 3, "subtype": 1, - "name": "entries", + "name": "Table", + "uri": "{/base}/finance/loan/table?{?}", + "target": "self", + "icon": null, + "order": 10, + "from": "LoanManagement", + "permission": { "permission": 2, "type": null, "element": null }, + "parent": 1008301001, + "children": [] + }, + { + "id": 1008305001, + "pid": "/finance/loan", + "type": 3, + "subtype": 1, + "name": "Entries", "uri": "{/base}/finance/loan/entry/list?{?}", "target": "self", "icon": null, diff --git a/Admin/Install/costtypes.json b/Admin/Install/costtypes.json new file mode 100644 index 0000000..b8ec469 --- /dev/null +++ b/Admin/Install/costtypes.json @@ -0,0 +1,51 @@ +[ + { + "name": "disagio", + "l11n": { + "en": "Disagio", + "de": "Disagio" + } + }, + { + "name": "interest", + "l11n": { + "en": "Interest", + "de": "Zinsen" + } + }, + { + "name": "repayment", + "l11n": { + "en": "Repayment", + "de": "Tilgung" + } + }, + { + "name": "unscheduled_repayment", + "l11n": { + "en": "Unscheduled repayment", + "de": "Sondertilgung" + } + }, + { + "name": "commitment_fee", + "l11n": { + "en": "Commitment fee", + "de": "Bereitstellungsgebühr" + } + }, + { + "name": "taxes", + "l11n": { + "en": "Taxes", + "de": "Steuern" + } + }, + { + "name": "other", + "l11n": { + "en": "Others", + "de": "Sonstige" + } + } +] \ No newline at end of file diff --git a/Admin/Install/db.json b/Admin/Install/db.json index 391780f..2c4cec3 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -1,4 +1,54 @@ { + "loanmgmt_cost_type": { + "name": "loanmgmt_cost_type", + "fields": { + "loanmgmt_cost_type_id": { + "name": "loanmgmt_cost_type_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "loanmgmt_cost_type_name": { + "name": "loanmgmt_cost_type_name", + "type": "VARCHAR(255)", + "null": false, + "unique": true + } + } + }, + "loanmgmt_cost_type_l11n": { + "name": "loanmgmt_cost_type_l11n", + "fields": { + "loanmgmt_cost_type_l11n_id": { + "name": "loanmgmt_cost_type_l11n_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "loanmgmt_cost_type_l11n_title": { + "name": "loanmgmt_cost_type_l11n_title", + "type": "VARCHAR(255)", + "null": false + }, + "loanmgmt_cost_type_l11n_type": { + "name": "loanmgmt_cost_type_l11n_type", + "type": "INT", + "null": false, + "foreignTable": "loanmgmt_cost_type", + "foreignKey": "loanmgmt_cost_type_id" + }, + "loanmgmt_cost_type_l11n_language": { + "name": "loanmgmt_cost_type_l11n_language", + "type": "VARCHAR(2)", + "default": null, + "null": true, + "foreignTable": "language", + "foreignKey": "language_639_1" + } + } + }, "loanmgmt_loan": { "name": "loanmgmt_loan", "fields": { @@ -9,6 +59,11 @@ "primary": true, "autoincrement": true }, + "loanmgmt_loan_start": { + "name": "loanmgmt_loan_start", + "type": "DATETIME", + "null": null + }, "loanmgmt_loan_title": { "name": "loanmgmt_loan_title", "type": "VARCHAR(255)", @@ -19,6 +74,59 @@ "type": "TEXT", "null": false }, + "loanmgmt_loan_payout_date": { + "name": "loanmgmt_loan_payout_date", + "type": "DATETIME", + "null": null + }, + "loanmgmt_loan_amount": { + "name": "loanmgmt_loan_amount", + "type": "BIGINT", + "null": false + }, + "loanmgmt_loan_disagio": { + "name": "loanmgmt_loan_disagio", + "type": "BIGINT", + "null": false + }, + "loanmgmt_loan_provision": { + "description": "Bereitstellungsgebuehr", + "name": "loanmgmt_loan_provision", + "type": "BIGINT", + "null": false + }, + "loanmgmt_loan_provision_rate": { + "description": "Bereitstellungsgebuehr", + "name": "loanmgmt_loan_provision_rate", + "type": "BIGINT", + "null": false + }, + "loanmgmt_loan_interest_start": { + "name": "loanmgmt_loan_interest_start", + "type": "DATETIME", + "null": null + }, + "loanmgmt_loan_interest_rate": { + "name": "loanmgmt_loan_interest_rate", + "type": "INT", + "null": false + }, + "loanmgmt_loan_interest_rate_post": { + "description": "Interest rate after binding period", + "name": "loanmgmt_loan_interest_rate_post", + "type": "INT", + "null": false + }, + "loanmgmt_loan_rate_binding": { + "name": "loanmgmt_loan_rate_binding", + "type": "INT", + "null": false + }, + "loanmgmt_loan_repayment_type": { + "name": "loanmgmt_loan_repayment_type", + "type": "TINYINT", + "null": false + }, "loanmgmt_loan_created_by": { "name": "loanmgmt_loan_created_by", "type": "INT", diff --git a/Admin/Installer.php b/Admin/Installer.php index 847d775..3af72e3 100755 --- a/Admin/Installer.php +++ b/Admin/Installer.php @@ -14,7 +14,12 @@ declare(strict_types=1); namespace Modules\LoanManagement\Admin; +use phpOMS\Application\ApplicationAbstract; +use phpOMS\Config\SettingsInterface; use phpOMS\Module\InstallerAbstract; +use phpOMS\Module\ModuleInfo; +use phpOMS\Message\Http\HttpRequest; +use phpOMS\Message\Http\HttpResponse; /** * Installer class. @@ -33,4 +38,82 @@ final class Installer extends InstallerAbstract * @since 1.0.0 */ public const PATH = __DIR__; + + /** + * {@inheritdoc} + */ + public static function install(ApplicationAbstract $app, ModuleInfo $info, SettingsInterface $cfgHandler) : void + { + parent::install($app, $info, $cfgHandler); + + /* Material types */ + $fileContent = \file_get_contents(__DIR__ . '/Install/costtypes.json'); + if ($fileContent === false) { + return; + } + + /** @var array $types */ + $types = \json_decode($fileContent, true); + $materialTypeArray = self::createCostTypes($app, $types); + } + + /** + * Install default material types + * + * @param ApplicationAbstract $app Application + * @param array $types Material type definitions + * + * @return array + * + * @since 1.0.0 + */ + private static function createCostTypes(ApplicationAbstract $app, array $types) : array + { + /** @var array $costType */ + $costType = []; + + /** @var \Modules\LoanManagement\Controller\ApiController $module */ + $module = $app->moduleManager->get('LoanManagement', 'Api'); + + /** @var array $type */ + foreach ($types as $type) { + $response = new HttpResponse(); + $request = new HttpRequest(); + + $request->header->account = 1; + $request->setData('name', $type['name'] ?? ''); + $request->setData('title', \reset($type['l11n'])); + + $module->apiLoanCostTypeCreate($request, $response); + + $responseData = $response->getData(''); + if (!\is_array($responseData)) { + continue; + } + + $costType[$type['name']] = \is_array($responseData['response']) + ? $responseData['response'] + : $responseData['response']->toArray(); + + $isFirst = true; + foreach ($type['l11n'] as $language => $l11n) { + if ($isFirst) { + $isFirst = false; + continue; + } + + $response = new HttpResponse(); + $request = new HttpRequest(); + + $request->header->account = 1; + $request->setData('title', $l11n); + $request->setData('language', $language); + $request->setData('type', $costType[$type['name']]['id']); + + $module->apiLoanCostTypeL11nCreate($request, $response); + } + } + + return $costType; + } } diff --git a/Controller/ApiController.php b/Controller/ApiController.php new file mode 100644 index 0000000..92e6a3a --- /dev/null +++ b/Controller/ApiController.php @@ -0,0 +1,221 @@ +validateCostTypeCreate($request))) { + $response->header->status = RequestStatusCode::R_400; + $this->createInvalidCreateResponse($request, $response, $val); + + return; + } + + $costType = $this->createCostTypeFromRequest($request); + $this->createModel($request->header->account, $costType, CostTypeMapper::class, 'cost_type', $request->getOrigin()); + $this->createStandardCreateResponse($request, $response, $costType); + } + + /** + * Validate cost create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateCostTypeCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['title'] = !$request->hasData('title')) + || ($val['name'] = !$request->hasData('name')) + ) { + return $val; + } + + return []; + } + + /** + * Method to create cost from request. + * + * @param RequestAbstract $request Request + * + * @return BaseStringL11nType + * + * @since 1.0.0 + */ + private function createCostTypeFromRequest(RequestAbstract $request) : BaseStringL11nType + { + $costType = new BaseStringL11nType($request->getDataString('name') ?? ''); + $costType->setL11n( + $request->getDataString('title') ?? '', + ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? ISO639x1Enum::_EN + ); + + return $costType; + } + + /** + * Api method to create item cost l11n + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param array $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiLoanCostTypeL11nCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void + { + if (!empty($val = $this->validateCostTypeL11nCreate($request))) { + $response->header->status = RequestStatusCode::R_400; + $this->createInvalidCreateResponse($request, $response, $val); + + return; + } + + $costL11n = $this->createCostTypeL11nFromRequest($request); + $this->createModel($request->header->account, $costL11n, CostTypeL11nMapper::class, 'cost_type_l11n', $request->getOrigin()); + $this->createStandardCreateResponse($request, $response, $costL11n); + } + + /** + * Validate cost l11n create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateCostTypeL11nCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['title'] = !$request->hasData('title')) + || ($val['type'] = !$request->hasData('type')) + ) { + return $val; + } + + return []; + } + + /** + * Method to create cost l11n from request. + * + * @param RequestAbstract $request Request + * + * @return BaseStringL11n + * + * @since 1.0.0 + */ + private function createCostTypeL11nFromRequest(RequestAbstract $request) : BaseStringL11n + { + $costL11n = new BaseStringL11n(); + $costL11n->ref = $request->getDataInt('type') ?? 0; + $costL11n->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $request->header->l11n->language; + $costL11n->content = $request->getDataString('title') ?? ''; + + return $costL11n; + } +} \ No newline at end of file diff --git a/Controller/BackendController.php b/Controller/BackendController.php index 7de9358..55a01c4 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -45,7 +45,49 @@ final class BackendController extends Controller { $view = new View($this->app->l11nManager, $request, $response); $view->setTemplate('/Modules/LoanManagement/Theme/Backend/loan-list'); - $view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1004601001, $request, $response); + $view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1008301001, $request, $response); + + return $view; + } + + /** + * Routing end-point for application behavior. + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param array $data Generic data + * + * @return RenderableInterface + * + * @since 1.0.0 + * @codeCoverageIgnore + */ + public function viewLoanCreate(RequestAbstract $request, ResponseAbstract $response, $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + $view->setTemplate('/Modules/LoanManagement/Theme/Backend/loan-list'); + $view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1008301001, $request, $response); + + return $view; + } + + /** + * Routing end-point for application behavior. + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param array $data Generic data + * + * @return RenderableInterface + * + * @since 1.0.0 + * @codeCoverageIgnore + */ + public function viewLoanTable(RequestAbstract $request, ResponseAbstract $response, $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + $view->setTemplate('/Modules/LoanManagement/Theme/Backend/loan-table'); + $view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1008301001, $request, $response); return $view; } diff --git a/Models/CostTypeL11nMapper.php b/Models/CostTypeL11nMapper.php new file mode 100644 index 0000000..c466260 --- /dev/null +++ b/Models/CostTypeL11nMapper.php @@ -0,0 +1,69 @@ + + */ +final class CostTypeL11nMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'loanmgmt_cost_type_l11n_id' => ['name' => 'loanmgmt_cost_type_l11n_id', 'type' => 'int', 'internal' => 'id'], + 'loanmgmt_cost_type_l11n_title' => ['name' => 'loanmgmt_cost_type_l11n_title', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true], + 'loanmgmt_cost_type_l11n_type' => ['name' => 'loanmgmt_cost_type_l11n_type', 'type' => 'int', 'internal' => 'ref'], + 'loanmgmt_cost_type_l11n_language' => ['name' => 'loanmgmt_cost_type_l11n_language', 'type' => 'string', 'internal' => 'language'], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'loanmgmt_cost_type_l11n'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'loanmgmt_cost_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/CostTypeMapper.php b/Models/CostTypeMapper.php new file mode 100644 index 0000000..48512e0 --- /dev/null +++ b/Models/CostTypeMapper.php @@ -0,0 +1,83 @@ + + */ +final class CostTypeMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'loanmgmt_cost_type_id' => ['name' => 'loanmgmt_cost_type_id', 'type' => 'int', 'internal' => 'id'], + 'loanmgmt_cost_type_name' => ['name' => 'loanmgmt_cost_type_name', 'type' => 'string', 'internal' => 'title', 'autocomplete' => true], + ]; + + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + public const HAS_MANY = [ + 'l11n' => [ + 'mapper' => CostTypeL11nMapper::class, + 'table' => 'loanmgmt_cost_type_l11n', + 'self' => 'loanmgmt_cost_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 = 'loanmgmt_cost_type'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'loanmgmt_cost_type_id'; +} diff --git a/Models/Loan.php b/Models/Loan.php index 7f60157..76fb58a 100755 --- a/Models/Loan.php +++ b/Models/Loan.php @@ -14,6 +14,9 @@ declare(strict_types=1); namespace Modules\LoanManagement\Models; +use Modules\SupplierManagement\Models\NullSupplier; +use Modules\SupplierManagement\Models\Supplier; + /** * Loan model. * @@ -30,6 +33,8 @@ class Loan public string $description = ''; + public Supplier $loanProvider; + public int $status = LoanStatus::DRAFT; public int $amount = 0; @@ -91,4 +96,12 @@ class Loan public array $taxes = []; public bool $hasManualTaxAmounts = false; + + public function __construct() + { + $this->loanProvider = new NullSupplier(); + $this->start = new \DateTime(); + $this->end = $this->start->modify('+1 year'); + $this->payout = $this->start; + } } diff --git a/Theme/Backend/Lang/en.lang.php b/Theme/Backend/Lang/en.lang.php index 77d7bde..eea00cc 100755 --- a/Theme/Backend/Lang/en.lang.php +++ b/Theme/Backend/Lang/en.lang.php @@ -13,4 +13,5 @@ declare(strict_types=1); return ['LoanManagement' => [ + 'Loans' => 'Loans' ]]; diff --git a/Theme/Backend/loan-list.tpl.php b/Theme/Backend/loan-list.tpl.php index ba439b3..ca2fa28 100755 --- a/Theme/Backend/loan-list.tpl.php +++ b/Theme/Backend/loan-list.tpl.php @@ -13,3 +13,4 @@ declare(strict_types=1); echo $this->data['nav']->render(); +?> \ No newline at end of file diff --git a/Theme/Backend/loan-table.tpl.php b/Theme/Backend/loan-table.tpl.php new file mode 100644 index 0000000..a4002b0 --- /dev/null +++ b/Theme/Backend/loan-table.tpl.php @@ -0,0 +1,51 @@ +data['nav']->render(); + +$length = \max(12, 12); +?> + +
+
+
+
getHtml('Loans'); ?>download
+
+ + + + + + + +
Loan + + + + +
Test + Interest
Other costs
Repayment
Payout + +
+ +
Test + Interest
Other costs
Repayment
Payout + +
+ +
Test + Interest
Other costs
Repayment
Payout + +
+ \ No newline at end of file