This commit is contained in:
Dennis Eichhorn 2024-03-10 02:24:56 +00:00
parent 5fc0432a27
commit 53ac925bfa
12 changed files with 743 additions and 5 deletions

View File

@ -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,

View File

@ -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"
}
}
]

View File

@ -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",

View File

@ -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<string, 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;
}
}

View File

@ -0,0 +1,221 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\LoanManagement
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\LoanManagement\Controller;
use Modules\LoanManagement\Models\CostTypeL11nMapper;
use Modules\LoanManagement\Models\CostTypeMapper;
use phpOMS\Localization\BaseStringL11n;
use phpOMS\Localization\BaseStringL11nType;
use phpOMS\Localization\ISO639x1Enum;
use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
/**
* LoanManagement class.
*
* @package Modules\LoanManagement
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
final class ApiController extends Controller
{
/**
* Api method to create tag
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiLoanCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
}
/**
* Api method to create tag
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiLoanTimelineCalculate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
}
/**
* Api method to create tag
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiLoanElementCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
}
/**
* Api method to create item cost type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param array $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiLoanCostTypeCreate(RequestAbstract $request, ResponseAbstract $response, array $data = []) : void
{
if (!empty($val = $this->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<string, bool>
*
* @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<string, bool>
*
* @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;
}
}

View File

@ -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;
}

View File

@ -0,0 +1,69 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\LoanManagement\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\LoanManagement\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
use phpOMS\Localization\BaseStringL11n;
/**
* Item mapper class.
*
* @package Modules\LoanManagement\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of BaseStringL11n
* @extends DataMapperFactory<T>
*/
final class CostTypeL11nMapper extends DataMapperFactory
{
/**
* Columns.
*
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?: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<T>
* @since 1.0.0
*/
public const MODEL = BaseStringL11n::class;
}

83
Models/CostTypeMapper.php Normal file
View File

@ -0,0 +1,83 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\LoanManagement\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\LoanManagement\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
use phpOMS\Localization\BaseStringL11nType;
/**
* Item mapper class.
*
* @package Modules\LoanManagement\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of BaseStringL11nType
* @extends DataMapperFactory<T>
*/
final class CostTypeMapper extends DataMapperFactory
{
/**
* Columns.
*
* @var array<string, array{name:string, type:string, internal:string, autocomplete?:bool, readonly?:bool, writeonly?:bool, annotations?: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<string, array{mapper:class-string, table:string, self?:?string, external?:?string, column?:string}>
* @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<T>
* @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';
}

View File

@ -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;
}
}

View File

@ -13,4 +13,5 @@
declare(strict_types=1);
return ['LoanManagement' => [
'Loans' => 'Loans'
]];

View File

@ -13,3 +13,4 @@
declare(strict_types=1);
echo $this->data['nav']->render();
?>

View File

@ -0,0 +1,51 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\LoanManagement
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
echo $this->data['nav']->render();
$length = \max(12, 12);
?>
<div class="row">
<div class="col-xs-12">
<section class="portlet">
<div class="portlet-head"><?= $this->getHtml('Loans'); ?><i class="g-icon download btn end-xs">download</i></div>
<div class="slider">
<table id="iVehicleList" class="default sticky">
<thead>
<tr>
<td>Loan
<td>
<?php for ($i = 0; $i < $length; ++$i) : ?>
<td>
<?php endfor; ?>
<tbody>
<tr>
<td>Test
<td><span>Interest</span><br><span>Other costs</span><br><span>Repayment</span><br><span>Payout</span>
<?php for ($i = 0; $i < $length; ++$i) : ?>
<td>
<?php endfor; ?>
<tr>
<td>Test
<td><span>Interest</span><br><span>Other costs</span><br><span>Repayment</span><br><span>Payout</span>
<?php for ($i = 0; $i < $length; ++$i) : ?>
<td>
<?php endfor; ?>
<tr>
<td>Test
<td><span>Interest</span><br><span>Other costs</span><br><span>Repayment</span><br><span>Payout</span>
<?php for ($i = 0; $i < $length; ++$i) : ?>
<td>
<?php endfor; ?>