test fixes fleet+expense tests

This commit is contained in:
Dennis Eichhorn 2023-05-19 02:26:10 +00:00
parent 52b5a982e8
commit b8cdda7246
33 changed files with 2709 additions and 10 deletions

View File

@ -0,0 +1,16 @@
[
{
"type": "collection",
"create_directory": true,
"name": "BusinessExpenses",
"virtualPath": "/Modules",
"user": 1
},
{
"type": "collection",
"create_directory": true,
"name": "Expense",
"virtualPath": "/Modules/BusinessExpenses",
"user": 1
}
]

43
Admin/Install/Media.php Normal file
View File

@ -0,0 +1,43 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Admin\Install
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Admin\Install;
use phpOMS\Application\ApplicationAbstract;
/**
* Media class.
*
* @package Modules\BusinessExpenses\Admin\Install
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Media
{
/**
* Install media providing
*
* @param ApplicationAbstract $app Application
* @param string $path Module path
*
* @return void
*
* @since 1.0.0
*/
public static function install(ApplicationAbstract $app, string $path) : void
{
\Modules\Media\Admin\Installer::installExternal($app, ['path' => __DIR__ . '/Media.install.json']);
}
}

View File

@ -5,7 +5,7 @@
"type": 2,
"subtype": 1,
"name": "BusinessExpenses",
"uri": "{/prefix}?{?}",
"uri": "{/base}/businessexpenses/list",
"target": "self",
"icon": null,
"order": 40,
@ -19,7 +19,7 @@
"type": 2,
"subtype": 1,
"name": "List",
"uri": "{/prefix}?{?}",
"uri": "{/base}/businessexpenses/list",
"target": "self",
"icon": null,
"order": 40,

View File

@ -14,7 +14,7 @@ declare(strict_types=1);
namespace Modules\BusinessExpenses\Admin\Install;
use phpOMS\DataStorage\Database\DatabasePool;
use phpOMS\Application\ApplicationAbstract;
/**
* Navigation class.
@ -29,15 +29,15 @@ class Navigation
/**
* Install navigation providing
*
* @param string $path Module path
* @param DatabasePool $dbPool Database pool for database interaction
* @param ApplicationAbstract $app Application
* @param string $path Module path
*
* @return void
*
* @since 1.0.0
*/
public static function install(string $path, DatabasePool $dbPool) : void
public static function install(ApplicationAbstract $app, string $path) : void
{
\Modules\Navigation\Admin\Installer::installExternal($dbPool, ['path' => __DIR__ . '/Navigation.install.json']);
\Modules\Navigation\Admin\Installer::installExternal($app, ['path' => __DIR__ . '/Navigation.install.json']);
}
}

333
Admin/Install/db.json Normal file
View File

@ -0,0 +1,333 @@
{
"bizexpenses_expense_type": {
"name": "bizexpenses_expense_type",
"fields": {
"bizexpenses_expense_type_id": {
"name": "bizexpenses_expense_type_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"bizexpenses_expense_type_name": {
"name": "bizexpenses_expense_type_name",
"type": "VARCHAR(255)",
"null": false
}
}
},
"bizexpenses_expense_type_l11n": {
"name": "bizexpenses_expense_type_l11n",
"fields": {
"bizexpenses_expense_type_l11n_id": {
"name": "bizexpenses_expense_type_l11n_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"bizexpenses_expense_type_l11n_title": {
"name": "bizexpenses_expense_type_l11n_title",
"type": "VARCHAR(255)",
"null": false
},
"bizexpenses_expense_type_l11n_type": {
"name": "bizexpenses_expense_type_l11n_type",
"type": "INT(11)",
"null": false,
"foreignTable": "bizexpenses_expense_type",
"foreignKey": "bizexpenses_expense_type_id"
},
"bizexpenses_expense_type_l11n_lang": {
"name": "bizexpenses_expense_type_l11n_lang",
"type": "VARCHAR(2)",
"null": false,
"foreignTable": "language",
"foreignKey": "language_639_1"
}
}
},
"bizexpenses_expense_element_type": {
"name": "bizexpenses_expense_element_type",
"fields": {
"bizexpenses_expense_element_type_id": {
"name": "bizexpenses_expense_element_type_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"bizexpenses_expense_element_type_name": {
"name": "bizexpenses_expense_element_type_name",
"type": "VARCHAR(255)",
"null": false
}
}
},
"bizexpenses_expense_element_type_l11n": {
"name": "bizexpenses_expense_element_type_l11n",
"fields": {
"bizexpenses_expense_element_type_l11n_id": {
"name": "bizexpenses_expense_element_type_l11n_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"bizexpenses_expense_element_type_l11n_title": {
"name": "bizexpenses_expense_element_type_l11n_title",
"type": "VARCHAR(255)",
"null": false
},
"bizexpenses_expense_element_type_l11n_type": {
"name": "bizexpenses_expense_element_type_l11n_type",
"type": "INT(11)",
"null": false,
"foreignTable": "bizexpenses_expense_element_type",
"foreignKey": "bizexpenses_expense_element_type_id"
},
"bizexpenses_expense_element_type_l11n_lang": {
"name": "bizexpenses_expense_element_type_l11n_lang",
"type": "VARCHAR(2)",
"null": false,
"foreignTable": "language",
"foreignKey": "language_639_1"
}
}
},
"bizexpenses_expense": {
"name": "bizexpenses_expense",
"fields": {
"bizexpenses_expense_id": {
"name": "bizexpenses_expense_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"bizexpenses_expense_status": {
"name": "bizexpenses_expense_status",
"type": "TINYINT(1)",
"null": false
},
"bizexpenses_expense_description": {
"name": "bizexpenses_expense_description",
"type": "TEXT",
"null": false
},
"bizexpenses_expense_approved": {
"name": "bizexpenses_expense_approved",
"type": "TINYINT(1)",
"null": false
},
"bizexpenses_expense_paid": {
"name": "bizexpenses_expense_paid",
"type": "TINYINT(1)",
"null": false
},
"bizexpenses_expense_net": {
"name": "bizexpenses_expense_net",
"type": "BIGINT",
"null": false
},
"bizexpenses_expense_gross": {
"name": "bizexpenses_expense_gross",
"type": "BIGINT",
"null": false
},
"bizexpenses_expense_taxp": {
"name": "bizexpenses_expense_taxP",
"type": "BIGINT",
"null": false
},
"bizexpenses_expense_created": {
"name": "bizexpenses_expense_created",
"type": "DATETIME",
"null": false
},
"bizexpenses_expense_start": {
"name": "bizexpenses_expense_start",
"type": "DATETIME",
"null": false
},
"bizexpenses_expense_end": {
"name": "bizexpenses_expense_end",
"type": "DATETIME",
"null": false
},
"bizexpenses_expense_type": {
"name": "bizexpenses_expense_type",
"type": "INT",
"null": false,
"foreignTable": "bizexpenses_expense_type",
"foreignKey": "bizexpenses_expense_type_id"
},
"bizexpenses_expense_from": {
"name": "bizexpenses_expense_from",
"type": "INT",
"null": false,
"foreignTable": "account",
"foreignKey": "account_id"
},
"bizexpenses_expense_country": {
"name": "bizexpenses_expense_country",
"type": "VARCHAR(2)",
"null": true,
"default": null,
"foreignTable": "country",
"foreignKey": "country_code2"
}
}
},
"bizexpenses_expense_element": {
"name": "bizexpenses_expense_element",
"fields": {
"bizexpenses_expense_element_id": {
"name": "bizexpenses_expense_element_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"bizexpenses_expense_element_description": {
"name": "bizexpenses_expense_element_description",
"type": "TEXT",
"null": false
},
"bizexpenses_expense_element_approved": {
"name": "bizexpenses_expense_element_approved",
"type": "TINYINT(1)",
"null": false
},
"bizexpenses_expense_element_net": {
"name": "bizexpenses_expense_element_net",
"type": "BIGINT",
"null": false
},
"bizexpenses_expense_element_gross": {
"name": "bizexpenses_expense_element_gross",
"type": "BIGINT",
"null": false
},
"bizexpenses_expense_element_taxp": {
"name": "bizexpenses_expense_element_taxp",
"type": "BIGINT",
"null": false
},
"bizexpenses_expense_element_taxr": {
"name": "bizexpenses_expense_element_taxr",
"type": "BIGINT",
"null": false
},
"bizexpenses_expense_element_quantity": {
"name": "bizexpenses_expense_element_quantity",
"type": "BIGINT",
"null": false
},
"bizexpenses_expense_element_taxid": {
"name": "bizexpenses_expense_element_taxid",
"type": "TEXT",
"null": false
},
"bizexpenses_expense_element_start": {
"name": "bizexpenses_expense_element_start",
"type": "DATETIME",
"null": false
},
"bizexpenses_expense_element_end": {
"name": "bizexpenses_expense_element_end",
"type": "DATETIME",
"null": false
},
"bizexpenses_expense_element_supplier": {
"name": "bizexpenses_expense_element_supplier",
"type": "INT",
"null": true,
"default": null,
"foreignTable": "suppliermgmt_supplier",
"foreignKey": "suppliermgmt_supplier_id"
},
"bizexpenses_expense_element_ref": {
"name": "bizexpenses_expense_element_ref",
"type": "INT",
"null": false,
"foreignTable": "account",
"foreignKey": "account_id"
},
"bizexpenses_expense_element_type": {
"name": "bizexpenses_expense_element_type",
"type": "INT",
"null": false,
"foreignTable": "bizexpenses_expense_element_type",
"foreignKey": "bizexpenses_expense_element_type_id"
},
"bizexpenses_expense_element_country": {
"name": "bizexpenses_expense_element_country",
"type": "VARCHAR(2)",
"null": true,
"default": null,
"foreignTable": "country",
"foreignKey": "country_code2"
},
"bizexpenses_expense_element_expense": {
"name": "bizexpenses_expense_element_expense",
"type": "INT",
"null": false,
"foreignTable": "bizexpenses_expense",
"foreignKey": "bizexpenses_expense_id"
}
}
},
"bizexpenses_expense_media": {
"name": "bizexpenses_expense_media",
"fields": {
"bizexpenses_expense_media_id": {
"name": "bizexpenses_expense_media_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"bizexpenses_expense_media_src": {
"name": "bizexpenses_expense_media_src",
"type": "INT",
"null": false,
"foreignTable": "bizexpenses_expense",
"foreignKey": "bizexpenses_expense_id"
},
"bizexpenses_expense_media_dst": {
"name": "bizexpenses_expense_media_dst",
"type": "INT",
"null": false,
"foreignTable": "media",
"foreignKey": "media_id"
}
}
},
"bizexpenses_expense_element_media": {
"name": "bizexpenses_expense_element_media",
"fields": {
"bizexpenses_expense_element_media_id": {
"name": "bizexpenses_expense_element_media_id",
"type": "INT",
"null": false,
"primary": true,
"autoincrement": true
},
"bizexpenses_expense_element_media_src": {
"name": "bizexpenses_expense_element_media_src",
"type": "INT",
"null": false,
"foreignTable": "bizexpenses_expense_element",
"foreignKey": "bizexpenses_expense_element_id"
},
"bizexpenses_expense_element_media_dst": {
"name": "bizexpenses_expense_element_media_dst",
"type": "INT",
"null": false,
"foreignTable": "media",
"foreignKey": "media_id"
}
}
}
}

View File

@ -0,0 +1,65 @@
[
{
"name": "fuel",
"l11n": {
"en": "Fuel",
"de": "Kraftstoff"
}
},
{
"name": "entertainment",
"l11n": {
"en": "Entertainment",
"de": "Unterhaltung"
}
},
{
"name": "breakfast",
"l11n": {
"en": "Breakfast",
"de": "Frühstück"
}
},
{
"name": "lunch",
"l11n": {
"en": "Lunch",
"de": "Mittagessen"
}
},
{
"name": "dinner",
"l11n": {
"en": "Dinner",
"de": "Abendessen"
}
},
{
"name": "hotel",
"l11n": {
"en": "Hotel",
"de": "Hotel"
}
},
{
"name": "travelling",
"l11n": {
"en": "Travelling (train, airplane, bus, taxi, ...)",
"de": "Reisen (Zug, Flugzeug, Bus, Taxi, ...)"
}
},
{
"name": "present",
"l11n": {
"en": "Present",
"de": "Geschenk"
}
},
{
"name": "other",
"l11n": {
"en": "Other",
"de": "Sonstiges"
}
}
]

View File

@ -0,0 +1,44 @@
[
{
"name": "sales",
"l11n": {
"en": "Sales",
"de": "Vertrieb"
}
},
{
"name": "supplier",
"l11n": {
"en": "Supplier",
"de": "Einkauf"
}
},
{
"name": "education",
"l11n": {
"en": "Education",
"de": "Fortbildung"
}
},
{
"name": "event",
"l11n": {
"en": "Event (e.g. conference, trade fair)",
"de": "Event (z.B. Konferenz, Messe)"
}
},
{
"name": "affiliate",
"l11n": {
"en": "Affiliates",
"de": "Verbundene Unternehmen"
}
},
{
"name": "other",
"l11n": {
"en": "Other",
"de": "Sonstiges"
}
}
]

View File

@ -14,7 +14,13 @@ declare(strict_types=1);
namespace Modules\BusinessExpenses\Admin;
use phpOMS\Application\ApplicationAbstract;
use phpOMS\Config\SettingsInterface;
use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\HttpResponse;
use phpOMS\Module\InstallerAbstract;
use phpOMS\Module\ModuleInfo;
use phpOMS\Uri\HttpUri;
/**
* Installer class.
@ -26,4 +32,161 @@ use phpOMS\Module\InstallerAbstract;
*/
final class Installer extends InstallerAbstract
{
/**
* Path of the file
*
* @var string
* @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);
/* Expense types */
$fileContent = \file_get_contents(__DIR__ . '/Install/expensetypes.json');
if ($fileContent === false) {
return;
}
/** @var array $types */
$types = \json_decode($fileContent, true);
$expenseTypes = self::createExpenseTypes($app, $types);
/* Element types */
$fileContent = \file_get_contents(__DIR__ . '/Install/elementtypes.json');
if ($fileContent === false) {
return;
}
/** @var array $types */
$types = \json_decode($fileContent, true);
$elementTypes = self::createExpenseElementTypes($app, $types);
}
/**
* Install fuel type
*
* @param ApplicationAbstract $app Application
* @param array<array{name:string, l11n?:array<string, string>, is_required?:bool, is_custom_allowed?:bool, validation_pattern?:string, value_type?:string, values?:array<string, mixed>}> $attributes Attribute definition
*
* @return array<string, array>
*
* @since 1.0.0
*/
private static function createExpenseTypes(ApplicationAbstract $app, array $types) : array
{
/** @var array<string, array> $expenseTypes */
$expenseTypes = [];
/** @var \Modules\BusinessExpenses\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('BusinessExpenses');
/** @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->apiExpenseTypeCreate($request, $response);
$responseData = $response->get('');
if (!\is_array($responseData)) {
continue;
}
$expenseTypes[$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', $expenseTypes[$type['name']]['id']);
$module->apiExpenseTypeL11nCreate($request, $response);
}
}
return $expenseTypes;
}
/**
* Install fuel type
*
* @param ApplicationAbstract $app Application
* @param array<array{name:string, l11n?:array<string, string>, is_required?:bool, is_custom_allowed?:bool, validation_pattern?:string, value_type?:string, values?:array<string, mixed>}> $attributes Attribute definition
*
* @return array<string, array>
*
* @since 1.0.0
*/
private static function createExpenseElementTypes(ApplicationAbstract $app, array $types) : array
{
/** @var array<string, array> $elementTypes */
$elementTypes = [];
/** @var \Modules\BusinessExpenses\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('BusinessExpenses');
/** @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->apiExpenseElementTypeCreate($request, $response);
$responseData = $response->get('');
if (!\is_array($responseData)) {
continue;
}
$elementTypes[$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', $elementTypes[$type['name']]['id']);
$module->apiExpenseElementTypeL11nCreate($request, $response);
}
}
return $elementTypes;
}
}

View File

@ -26,4 +26,11 @@ use phpOMS\Module\StatusAbstract;
*/
final class Status extends StatusAbstract
{
/**
* Path of the file
*
* @var string
* @since 1.0.0
*/
public const PATH = __DIR__;
}

View File

@ -26,4 +26,11 @@ use phpOMS\Module\UninstallerAbstract;
*/
final class Uninstaller extends UninstallerAbstract
{
/**
* Path of the file
*
* @var string
* @since 1.0.0
*/
public const PATH = __DIR__;
}

View File

@ -26,4 +26,11 @@ use phpOMS\Module\UpdaterAbstract;
*/
final class Updater extends UpdaterAbstract
{
/**
* Path of the file
*
* @var string
* @since 1.0.0
*/
public const PATH = __DIR__;
}

688
Controller/ApiController.php Executable file
View File

@ -0,0 +1,688 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Controller;
use Modules\Admin\Models\AccountMapper;
use Modules\Admin\Models\NullAccount;
use Modules\BusinessExpenses\Models\Expense;
use Modules\BusinessExpenses\Models\ExpenseElement;
use Modules\BusinessExpenses\Models\ExpenseElementMapper;
use Modules\BusinessExpenses\Models\ExpenseElementTypeL11nMapper;
use Modules\BusinessExpenses\Models\ExpenseElementTypeMapper;
use Modules\BusinessExpenses\Models\ExpenseMapper;
use Modules\BusinessExpenses\Models\ExpenseStatus;
use Modules\BusinessExpenses\Models\ExpenseType;
use Modules\BusinessExpenses\Models\ExpenseTypeL11nMapper;
use Modules\BusinessExpenses\Models\NullExpenseType;
use Modules\BusinessExpenses\Models\ExpenseTypeMapper;
use Modules\BusinessExpenses\Models\NullExpenseElementType;
use Modules\Media\Models\CollectionMapper;
use Modules\Media\Models\MediaMapper;
use Modules\Media\Models\PathSettings;
use Modules\SupplierManagement\Models\NullSupplier;
use phpOMS\Localization\BaseStringL11n;
use phpOMS\Localization\ISO639x1Enum;
use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\Message\NotificationLevel;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
use phpOMS\Model\Message\FormValidation;
use phpOMS\Stdlib\Base\FloatInt;
/**
* BusinessExpenses class.
*
* @package Modules\BusinessExpenses
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
final class ApiController extends Controller
{
/**
* Api method to create a type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiExpenseTypeCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
if (!empty($val = $this->validateExpenseTypeCreate($request))) {
$response->set($request->uri->__toString(), new FormValidation($val));
$response->header->status = RequestStatusCode::R_400;
return;
}
/** @var ExpenseType $type */
$type = $this->createExpenseTypeFromRequest($request);
$this->createModel($request->header->account, $type, ExpenseTypeMapper::class, 'expense_type', $request->getOrigin());
$this->fillJsonResponse(
$request,
$response,
NotificationLevel::OK,
'',
$this->app->l11nManager->getText($response->getLanguage(), '0', '0', 'SucessfulCreate'),
$type
);
}
/**
* Method to create type from request.
*
* @param RequestAbstract $request Request
*
* @return ExpenseType Returns the created type from the request
*
* @since 1.0.0
*/
public function createExpenseTypeFromRequest(RequestAbstract $request) : ExpenseType
{
$type = new ExpenseType();
$type->name = $request->getDataString('name') ?? '';
$type->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN);
return $type;
}
/**
* Validate type create request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool> Returns the validation array of the request
*
* @since 1.0.0
*/
private function validateExpenseTypeCreate(RequestAbstract $request) : array
{
$val = [];
if (($val['name'] = !$request->hasData('name'))
|| ($val['title'] = !$request->hasData('title'))
) {
return $val;
}
return [];
}
/**
* Api method to create expense attribute l11n
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiExpenseTypeL11nCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
if (!empty($val = $this->validateExpenseTypeL11nCreate($request))) {
$response->set('expense_type_l11n_create', new FormValidation($val));
$response->header->status = RequestStatusCode::R_400;
return;
}
$typeL11n = $this->createExpenseTypeL11nFromRequest($request);
$this->createModel($request->header->account, $typeL11n, ExpenseTypeL11nMapper::class, 'expense_type_l11n', $request->getOrigin());
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Localization', 'Localization successfully created', $typeL11n);
}
/**
* Method to create expense attribute l11n from request.
*
* @param RequestAbstract $request Request
*
* @return BaseStringL11n
*
* @since 1.0.0
*/
private function createExpenseTypeL11nFromRequest(RequestAbstract $request) : BaseStringL11n
{
$typeL11n = new BaseStringL11n();
$typeL11n->ref = $request->getDataInt('type') ?? 0;
$typeL11n->setLanguage(
$request->getDataString('language') ?? $request->getLanguage()
);
$typeL11n->content = $request->getDataString('title') ?? '';
return $typeL11n;
}
/**
* Validate expense attribute l11n create request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool>
*
* @since 1.0.0
*/
private function validateExpenseTypeL11nCreate(RequestAbstract $request) : array
{
$val = [];
if (($val['title'] = !$request->hasData('title'))
|| ($val['type'] = !$request->hasData('type'))
) {
return $val;
}
return [];
}
/**
* Api method to create a type
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiExpenseElementTypeCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
if (!empty($val = $this->validateExpenseElementTypeCreate($request))) {
$response->set($request->uri->__toString(), new FormValidation($val));
$response->header->status = RequestStatusCode::R_400;
return;
}
/** @var ExpenseType $type */
$type = $this->createExpenseElementTypeFromRequest($request);
$this->createModel($request->header->account, $type, ExpenseElementTypeMapper::class, 'expense_element_type', $request->getOrigin());
$this->fillJsonResponse(
$request,
$response,
NotificationLevel::OK,
'',
$this->app->l11nManager->getText($response->getLanguage(), '0', '0', 'SucessfulCreate'),
$type
);
}
/**
* Method to create type from request.
*
* @param RequestAbstract $request Request
*
* @return ExpenseType Returns the created type from the request
*
* @since 1.0.0
*/
public function createExpenseElementTypeFromRequest(RequestAbstract $request) : ExpenseType
{
$type = new ExpenseType();
$type->name = $request->getDataString('name') ?? '';
$type->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN);
return $type;
}
/**
* Validate type create request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool> Returns the validation array of the request
*
* @since 1.0.0
*/
private function validateExpenseElementTypeCreate(RequestAbstract $request) : array
{
$val = [];
if (($val['name'] = !$request->hasData('name'))
|| ($val['title'] = !$request->hasData('title'))
) {
return $val;
}
return [];
}
/**
* Api method to create expense attribute l11n
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiExpenseElementTypeL11nCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
if (!empty($val = $this->validateExpenseElementTypeL11nCreate($request))) {
$response->set('expense_element_type_l11n_create', new FormValidation($val));
$response->header->status = RequestStatusCode::R_400;
return;
}
$typeL11n = $this->createExpenseElementTypeL11nFromRequest($request);
$this->createModel($request->header->account, $typeL11n, ExpenseElementTypeL11nMapper::class, 'expense_element_type_l11n', $request->getOrigin());
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Localization', 'Localization successfully created', $typeL11n);
}
/**
* Method to create expense attribute l11n from request.
*
* @param RequestAbstract $request Request
*
* @return BaseStringL11n
*
* @since 1.0.0
*/
private function createExpenseElementTypeL11nFromRequest(RequestAbstract $request) : BaseStringL11n
{
$typeL11n = new BaseStringL11n();
$typeL11n->ref = $request->getDataInt('type') ?? 0;
$typeL11n->setLanguage(
$request->getDataString('language') ?? $request->getLanguage()
);
$typeL11n->content = $request->getDataString('title') ?? '';
return $typeL11n;
}
/**
* Validate expense attribute l11n create request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool>
*
* @since 1.0.0
*/
private function validateExpenseElementTypeL11nCreate(RequestAbstract $request) : array
{
$val = [];
if (($val['title'] = !$request->hasData('title'))
|| ($val['type'] = !$request->hasData('type'))
) {
return $val;
}
return [];
}
/**
* Api method to create expense attribute l11n
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiExpenseCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
if (!empty($val = $this->validateExpenseCreate($request))) {
$response->set('expense_create', new FormValidation($val));
$response->header->status = RequestStatusCode::R_400;
return;
}
$expense = $this->createExpenseFromRequest($request);
$this->createModel($request->header->account, $expense, ExpenseMapper::class, 'expense', $request->getOrigin());
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Expense', 'Successfully created', $expense);
}
/**
* Method to create expense attribute l11n from request.
*
* @param RequestAbstract $request Request
*
* @return Expense
*
* @since 1.0.0
*/
private function createExpenseFromRequest(RequestAbstract $request) : Expense
{
$expense = new Expense();
$expense->from = new NullAccount((int) $request->header->account);
$expense->type = new NullExpenseType((int) $request->getDataInt('type'));
$expense->status = (int) ($request->getDataInt('status') ?? ExpenseStatus::DRAFT);
$expense->description = $request->getDataString('description') ?? '';
$country = $request->getDataString('country') ?? '';
if (empty($country)) {
$account = $this->app->accountManager->get($request->header->account);
if ($account->id === 0) {
$account = AccountMapper::get()->with('l11n')->where('id', $request->header->account)->execute();
}
$country = $account->l11n->country;
}
$expense->country = $country;
return $expense;
}
/**
* Validate expense attribute l11n create request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool>
*
* @since 1.0.0
*/
private function validateExpenseCreate(RequestAbstract $request) : array
{
$val = [];
if (($val['type'] = !$request->hasData('type'))
) {
return $val;
}
return [];
}
/**
* Api method to create expense attribute l11n
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiExpenseElementCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
if (!empty($val = $this->validateExpenseElementCreate($request))) {
$response->set('expense_element_create', new FormValidation($val));
$response->header->status = RequestStatusCode::R_400;
return;
}
$element = $this->createExpenseElementFromRequest($request);
$this->createModel($request->header->account, $element, ExpenseElementMapper::class, 'expense_element', $request->getOrigin());
if ($request->hasFiles()) {
$request->setData('element', $element->id, true);
$this->apiMediaAddToExpenseElement($request, $response, $data);
// @todo: refill element with parsed data from media (ocr)
}
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Element', 'Successfully created', $element);
}
/**
* Method to create expense attribute l11n from request.
*
* @param RequestAbstract $request Request
*
* @return ExpenseElement
*
* @since 1.0.0
*/
private function createExpenseElementFromRequest(RequestAbstract $request) : ExpenseElement
{
$element = new ExpenseElement();
$element->expense = (int) $request->getData('expense');
$element->description = $request->getDataString('description') ?? '';
$element->type = new NullExpenseElementType((int) $request->getData('type'));
// @todo: fill from media if available
// @todo: handle different value set (net, gross, taxr, ...).
// Depending on the value set the other values should be calculated
$element->net = new FloatInt($request->getDataInt('net') ?? 0);
$element->taxR = new FloatInt($request->getDataInt('taxr') ?? 0);
$element->taxP = new FloatInt($request->getDataInt('taxp') ?? 0);
$element->gross = new FloatInt($request->getDataInt('gross') ?? 0);
$element->quantity = new FloatInt($request->getDataInt('quantity') ?? 0);
if ($request->hasData('supplier')) {
$element->supplier = new NullSupplier((int) $request->getData('supplier'));
}
// @todo: use country of expense if no country is set
$country = $request->getDataString('country') ?? '';
if (empty($country)) {
$account = $this->app->accountManager->get($request->header->account);
if ($account->id === 0) {
$account = AccountMapper::get()->with('l11n')->where('id', $request->header->account)->execute();
}
$country = $account->l11n->country;
}
$element->country = $country;
return $element;
}
/**
* 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 apiMediaAddToExpenseElement(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
if (!empty($val = $this->validateMediaAddToExpenseElement($request))) {
$response->set($request->uri->__toString(), new FormValidation($val));
$response->header->status = RequestStatusCode::R_400;
return;
}
/** @var \Modules\BusinessExpenses\Models\Expense $expense */
$expense = ExpenseMapper::get()->where('id', (int) $request->getData('expense'))->execute();
$path = $this->createExpenseDir($expense);
$element = (int) $request->getData('element');
$uploaded = [];
if (!empty($uploadedFiles = $request->getFiles())) {
$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,
$element,
$media->id,
ExpenseElementMapper::class,
'media',
'',
$request->getOrigin()
);
if ($request->hasData('type')) {
$this->createModelRelation(
$request->header->account,
$media->id,
$request->getDataInt('type'),
MediaMapper::class,
'types',
'',
$request->getOrigin()
);
}
if ($collection === null) {
$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,
$element,
(int) $media,
ExpenseElementMapper::class,
'media',
'',
$request->getOrigin()
);
}
}
$this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Media', 'Media added to bill.', [
'upload' => $uploaded,
'media' => $mediaFiles,
]);
}
/**
* Method to validate bill creation from request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool>
*
* @since 1.0.0
*/
private function validateMediaAddToExpenseElement(RequestAbstract $request) : array
{
$val = [];
if (($val['media'] = (!$request->hasData('media') && empty($request->getFiles())))
|| ($val['expense'] = !$request->hasData('expense'))
|| ($val['element'] = !$request->hasData('element'))
) {
return $val;
}
return [];
}
/**
* Validate expense attribute l11n create request
*
* @param RequestAbstract $request Request
*
* @return array<string, bool>
*
* @since 1.0.0
*/
private function validateExpenseElementCreate(RequestAbstract $request) : array
{
$val = [];
if (($val['expense'] = !$request->hasData('expense'))
|| ($val['type'] = !$request->hasData('type'))
) {
return $val;
}
return [];
}
/**
* Create media directory path
*
* @param Expense $expense Expense
*
* @return string
*
* @since 1.0.0
*/
private function createExpenseDir(Expense $expense) : string
{
return '/Modules/BusinessExpenses/Expense/'
. $this->app->unitId . '/'
. $expense->createdAt->format('Y/m/d') . '/'
. $expense->id;
}
/**
* Api method to create bill files
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $data Generic data
*
* @return void
*
* @api
*
* @since 1.0.0
*/
public function apiExpenseFromUpload(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void
{
}
}

View File

@ -0,0 +1,76 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Controller;
use phpOMS\Contract\RenderableInterface;
use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract;
use phpOMS\Views\View;
/**
* BusinessExpenses class.
*
* @package Modules\BusinessExpenses
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
* @codeCoverageIgnore
*/
final class BackendController extends Controller
{
/**
* Routing end-point for application behaviour.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $data Generic data
*
* @return RenderableInterface Returns a renderable object
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewBusinessExpensesList(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/BusinessExpenses/Theme/Backend/expense-list');
$view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1001001001, $request, $response));
return $view;
}
/**
* Routing end-point for application behaviour.
*
* @param RequestAbstract $request Request
* @param ResponseAbstract $response Response
* @param mixed $data Generic data
*
* @return RenderableInterface Returns a renderable object
*
* @since 1.0.0
* @codeCoverageIgnore
*/
public function viewBusinessExpensesExpense(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface
{
$view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/BusinessExpenses/Theme/Backend/expenses-profile');
$view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1001001001, $request, $response));
return $view;
}
}

76
Controller/Controller.php Executable file
View File

@ -0,0 +1,76 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Controller;
use phpOMS\Module\ModuleAbstract;
/**
* BusinessExpenses class.
*
* @package Modules\BusinessExpenses
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Controller extends ModuleAbstract
{
/**
* Module path.
*
* @var string
* @since 1.0.0
*/
public const PATH = __DIR__ . '/../';
/**
* Module version.
*
* @var string
* @since 1.0.0
*/
public const VERSION = '1.0.0';
/**
* Module name.
*
* @var string
* @since 1.0.0
*/
public const NAME = 'BusinessExpenses';
/**
* Module id.
*
* @var int
* @since 1.0.0
*/
public const ID = 1001000000;
/**
* Providing.
*
* @var string[]
* @since 1.0.0
*/
protected static array $providing = [];
/**
* Dependencies.
*
* @var string[]
* @since 1.0.0
*/
protected static array $dependencies = [];
}

78
Models/Expense.php Normal file
View File

@ -0,0 +1,78 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
use Modules\Admin\Models\Account;
use phpOMS\Localization\ISO3166TwoEnum;
use phpOMS\Stdlib\Base\FloatInt;
/**
* Expense class.
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class Expense {
public int $id = 0;
public Account $from;
public int $status = ExpenseStatus::DRAFT;
public ExpenseType $type;
public string $description = '';
public bool $approved = false;
public bool $paid = false;
/**
* Elements/costs
*
* @var ExpenseElement[]
* @since 1.0.0
*/
public array $elements = [];
public array $media = [];
public FloatInt $net;
public FloatInt $gross;
public FloatInt $taxP;
public \DateTime $start;
public \DateTime $end;
public \DateTimeImmutable $createdAt;
public string $country = ISO3166TwoEnum::_USA;
public function __construct()
{
$this->type = new ExpenseType();
$this->start = new \DateTime('now');
$this->end = new \DateTime('now');
$this->createdAt = new \DateTimeImmutable('now');
$this->from = new Account();
$this->net = new FloatInt();
$this->gross = new FloatInt();
$this->taxP = new FloatInt();
}
}

77
Models/ExpenseElement.php Normal file
View File

@ -0,0 +1,77 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
use Modules\Admin\Models\Account;
use Modules\SupplierManagement\Models\Supplier;
use phpOMS\Localization\ISO3166TwoEnum;
use phpOMS\Stdlib\Base\FloatInt;
/**
* Expense class.
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class ExpenseElement
{
public int $id = 0;
public int $expense = 0;
public bool $approved = false;
public string $description = '';
public FloatInt $net;
public FloatInt $taxR;
public FloatInt $taxP;
public FloatInt $gross;
public FloatInt $quantity;
public ExpenseElementType $type;
public ?Account $ref = null;
public array $media = [];
public string $taxId = '';
public ?Supplier $supplier = null;
public string $country = ISO3166TwoEnum::_USA;
public \DateTime $start;
public \DateTime $end;
public function __construct()
{
$this->type = new ExpenseElementType();
$this->net = new FloatInt();
$this->taxR = new FloatInt();
$this->taxP = new FloatInt();
$this->gross = new FloatInt();
$this->quantity = new FloatInt();
$this->start = new \DateTime('now');
$this->end = new \DateTime('now');
}
}

View File

@ -0,0 +1,128 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
use Modules\Admin\Models\AccountMapper;
use Modules\Media\Models\MediaMapper;
use Modules\SupplierManagement\Models\SupplierMapper;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
* mapper class.
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of BaseStringL11n
* @extends DataMapperFactory<T>
*/
final class ExpenseElementMapper 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 = [
'bizexpenses_expense_element_id' => ['name' => 'bizexpenses_expense_element_id', 'type' => 'int', 'internal' => 'id'],
'bizexpenses_expense_element_description' => ['name' => 'bizexpenses_expense_element_description', 'type' => 'string', 'internal' => 'description'],
'bizexpenses_expense_element_approved' => ['name' => 'bizexpenses_expense_element_approved', 'type' => 'bool', 'internal' => 'approved'],
'bizexpenses_expense_element_net' => ['name' => 'bizexpenses_expense_element_net', 'type' => 'Serializable', 'internal' => 'net'],
'bizexpenses_expense_element_gross' => ['name' => 'bizexpenses_expense_element_gross', 'type' => 'Serializable', 'internal' => 'gross'],
'bizexpenses_expense_element_taxp' => ['name' => 'bizexpenses_expense_element_taxp', 'type' => 'Serializable', 'internal' => 'taxP'],
'bizexpenses_expense_element_taxr' => ['name' => 'bizexpenses_expense_element_taxr', 'type' => 'Serializable', 'internal' => 'taxR'],
'bizexpenses_expense_element_quantity' => ['name' => 'bizexpenses_expense_element_quantity', 'type' => 'Serializable', 'internal' => 'quantity'],
'bizexpenses_expense_element_taxid' => ['name' => 'bizexpenses_expense_element_taxid', 'type' => 'string', 'internal' => 'taxId'],
'bizexpenses_expense_element_start' => ['name' => 'bizexpenses_expense_element_start', 'type' => 'DateTime', 'internal' => 'start'],
'bizexpenses_expense_element_end' => ['name' => 'bizexpenses_expense_element_end', 'type' => 'DateTime', 'internal' => 'end'],
'bizexpenses_expense_element_supplier' => ['name' => 'bizexpenses_expense_element_supplier', 'type' => 'int', 'internal' => 'supplier'],
'bizexpenses_expense_element_ref' => ['name' => 'bizexpenses_expense_element_ref', 'type' => 'int', 'internal' => 'ref'],
'bizexpenses_expense_element_type' => ['name' => 'bizexpenses_expense_element_type', 'type' => 'int', 'internal' => 'type'],
'bizexpenses_expense_element_country' => ['name' => 'bizexpenses_expense_element_country', 'type' => 'string', 'internal' => 'country'],
'bizexpenses_expense_element_expense' => ['name' => 'bizexpenses_expense_element_expense', 'type' => 'int', 'internal' => 'expense'],
];
/**
* 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 = [
'media' => [
'mapper' => MediaMapper::class,
'table' => 'bizexpenses_expense_element_media',
'external' => 'bizexpenses_expense_element_media_dst',
'self' => 'bizexpenses_expense_element_media_src',
],
];
/**
* Belongs to.
*
* @var array<string, array{mapper:class-string, external:string, column?:string, by?:string}>
* @since 1.0.0
*/
public const BELONGS_TO = [
'ref' => [
'mapper' => AccountMapper::class,
'external' => 'bizexpenses_expense_element_ref',
],
'supplier' => [
'mapper' => SupplierMapper::class,
'external' => 'bizexpenses_expense_element_supplier',
],
];
/**
* Has one relation.
*
* @var array<string, array{mapper:class-string, external:string, by?:string, column?:string, conditional?:bool}>
* @since 1.0.0
*/
public const OWNS_ONE = [
'type' => [
'mapper' => ExpenseElementTypeMapper::class,
'external' => 'bizexpenses_expense_element_type',
],
];
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'bizexpenses_expense_element';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'bizexpenses_expense_element_id';
/**
* Model to use by the mapper.
*
* @var class-string<T>
* @since 1.0.0
*/
public const MODEL = BaseStringL11n::class;
}

View File

@ -0,0 +1,121 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
use phpOMS\Localization\BaseStringL11n;
use phpOMS\Localization\ISO639x1Enum;
/**
* Expense Type class.
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class ExpenseElementType implements \JsonSerializable
{
/**
* Id
*
* @var int
* @since 1.0.0
*/
public int $id = 0;
/**
* Name/string identifier by which it can be found/categorized
*
* @var string
* @since 1.0.0
*/
public string $name = '';
/**
* Localization
*
* @var BaseStringL11n
*/
public string | BaseStringL11n $l11n = '';
/**
* Constructor.
*
* @param string $name Name/identifier of the attribute type
*
* @since 1.0.0
*/
public function __construct(string $name = '')
{
$this->name = $name;
}
/**
* Set l11n
*
* @param string|BaseStringL11n $l11n Tag article l11n
* @param string $lang Language
*
* @return void
*
* @since 1.0.0
*/
public function setL11n(string | BaseStringL11n $l11n, string $lang = ISO639x1Enum::_EN) : void
{
if ($l11n instanceof BaseStringL11n) {
$this->l11n = $l11n;
} elseif (isset($this->l11n) && $this->l11n instanceof BaseStringL11n) {
$this->l11n->content = $l11n;
$this->l11n->setLanguage($lang);
} else {
$this->l11n = new BaseStringL11n();
$this->l11n->content = $l11n;
$this->l11n->setLanguage($lang);
}
}
/**
* @return string
*
* @since 1.0.0
*/
public function getL11n() : string
{
if (!isset($this->l11n)) {
return '';
}
return $this->l11n instanceof BaseStringL11n ? $this->l11n->content : $this->l11n;
}
/**
* {@inheritdoc}
*/
public function toArray() : array
{
return [
'id' => $this->id,
'name' => $this->name,
];
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return $this->toArray();
}
}

View File

@ -0,0 +1,69 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
use phpOMS\Localization\BaseStringL11n;
/**
* mapper class.
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of BaseStringL11n
* @extends DataMapperFactory<T>
*/
final class ExpenseElementTypeL11nMapper 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 = [
'bizexpenses_expense_element_type_l11n_id' => ['name' => 'bizexpenses_expense_element_type_l11n_id', 'type' => 'int', 'internal' => 'id'],
'bizexpenses_expense_element_type_l11n_title' => ['name' => 'bizexpenses_expense_element_type_l11n_title', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'bizexpenses_expense_element_type_l11n_type' => ['name' => 'bizexpenses_expense_element_type_l11n_type', 'type' => 'int', 'internal' => 'ref'],
'bizexpenses_expense_element_type_l11n_lang' => ['name' => 'bizexpenses_expense_element_type_l11n_lang', 'type' => 'string', 'internal' => 'language'],
];
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'bizexpenses_expense_element_type_l11n';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'bizexpenses_expense_element_type_l11n_id';
/**
* Model to use by the mapper.
*
* @var class-string<T>
* @since 1.0.0
*/
public const MODEL = BaseStringL11n::class;
}

View File

@ -0,0 +1,82 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
* Item mapper class.
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of ExpenseType
* @extends DataMapperFactory<T>
*/
final class ExpenseElementTypeMapper 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 = [
'bizexpenses_expense_element_type_id' => ['name' => 'bizexpenses_expense_element_type_id', 'type' => 'int', 'internal' => 'id'],
'bizexpenses_expense_element_type_name' => ['name' => 'bizexpenses_expense_element_type_name', 'type' => 'string', 'internal' => 'name', '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' => ExpenseElementTypeL11nMapper::class,
'table' => 'bizexpenses_expense_element_type_l11n',
'self' => 'bizexpenses_expense_element_type_l11n_type',
'column' => 'content',
'external' => null,
],
];
/**
* Model to use by the mapper.
*
* @var class-string<T>
* @since 1.0.0
*/
public const MODEL = ExpenseElementType::class;
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'bizexpenses_expense_element_type';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'bizexpenses_expense_element_type_id';
}

127
Models/ExpenseMapper.php Normal file
View File

@ -0,0 +1,127 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
use Modules\Admin\Models\AccountMapper;
use Modules\Media\Models\MediaMapper;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
* mapper class.
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of BaseStringL11n
* @extends DataMapperFactory<T>
*/
final class ExpenseMapper 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 = [
'bizexpenses_expense_id' => ['name' => 'bizexpenses_expense_id', 'type' => 'int', 'internal' => 'id'],
'bizexpenses_expense_status' => ['name' => 'bizexpenses_expense_status', 'type' => 'int', 'internal' => 'status'],
'bizexpenses_expense_description' => ['name' => 'bizexpenses_expense_description', 'type' => 'string', 'internal' => 'description'],
'bizexpenses_expense_approved' => ['name' => 'bizexpenses_expense_approved', 'type' => 'bool', 'internal' => 'approved'],
'bizexpenses_expense_paid' => ['name' => 'bizexpenses_expense_paid', 'type' => 'bool', 'internal' => 'paid'],
'bizexpenses_expense_net' => ['name' => 'bizexpenses_expense_net', 'type' => 'Serializable', 'internal' => 'net'],
'bizexpenses_expense_gross' => ['name' => 'bizexpenses_expense_gross', 'type' => 'Serializable', 'internal' => 'gross'],
'bizexpenses_expense_taxp' => ['name' => 'bizexpenses_expense_taxp', 'type' => 'Serializable', 'internal' => 'taxP'],
'bizexpenses_expense_created' => ['name' => 'bizexpenses_expense_created', 'type' => 'DateTimeImmutable', 'internal' => 'createdAt'],
'bizexpenses_expense_start' => ['name' => 'bizexpenses_expense_start', 'type' => 'DateTime', 'internal' => 'start'],
'bizexpenses_expense_end' => ['name' => 'bizexpenses_expense_end', 'type' => 'DateTime', 'internal' => 'end'],
'bizexpenses_expense_type' => ['name' => 'bizexpenses_expense_type', 'type' => 'int', 'internal' => 'type'],
'bizexpenses_expense_from' => ['name' => 'bizexpenses_expense_from', 'type' => 'int', 'internal' => 'from'],
'bizexpenses_expense_country' => ['name' => 'bizexpenses_expense_country', 'type' => 'string', 'internal' => 'country'],
];
/**
* 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 = [
'elements' => [
'mapper' => ExpenseElementMapper::class,
'table' => 'bizexpenses_expense_element',
'self' => 'bizexpenses_expense_element_expense',
'external' => null,
],
'media' => [
'mapper' => MediaMapper::class,
'table' => 'bizexpenses_expense_media',
'external' => 'bizexpenses_expense_media_dst',
'self' => 'bizexpenses_expense_media_src',
],
];
/**
* Belongs to.
*
* @var array<string, array{mapper:class-string, external:string, column?:string, by?:string}>
* @since 1.0.0
*/
public const BELONGS_TO = [
'from' => [
'mapper' => AccountMapper::class,
'external' => 'bizexpenses_expense_from',
],
];
/**
* Has one relation.
*
* @var array<string, array{mapper:class-string, external:string, by?:string, column?:string, conditional?:bool}>
* @since 1.0.0
*/
public const OWNS_ONE = [
'type' => [
'mapper' => ExpenseTypeMapper::class,
'external' => 'bizexpenses_expense_type',
],
];
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'bizexpenses_expense';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'bizexpenses_expense_id';
/**
* Model to use by the mapper.
*
* @var class-string<T>
* @since 1.0.0
*/
public const MODEL = Expense::class;
}

34
Models/ExpenseStatus.php Normal file
View File

@ -0,0 +1,34 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
use phpOMS\Stdlib\Base\Enum;
/**
* Expense status enum.
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
abstract class ExpenseStatus extends Enum
{
public const DRAFT = 1;
public const FINALIZED = 2;
public const INACTIVE = 3;
}

121
Models/ExpenseType.php Normal file
View File

@ -0,0 +1,121 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
use phpOMS\Localization\BaseStringL11n;
use phpOMS\Localization\ISO639x1Enum;
/**
* Expense Type class.
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class ExpenseType implements \JsonSerializable
{
/**
* Id
*
* @var int
* @since 1.0.0
*/
public int $id = 0;
/**
* Name/string identifier by which it can be found/categorized
*
* @var string
* @since 1.0.0
*/
public string $name = '';
/**
* Localization
*
* @var BaseStringL11n
*/
public string | BaseStringL11n $l11n = '';
/**
* Constructor.
*
* @param string $name Name/identifier of the attribute type
*
* @since 1.0.0
*/
public function __construct(string $name = '')
{
$this->name = $name;
}
/**
* Set l11n
*
* @param string|BaseStringL11n $l11n Tag article l11n
* @param string $lang Language
*
* @return void
*
* @since 1.0.0
*/
public function setL11n(string | BaseStringL11n $l11n, string $lang = ISO639x1Enum::_EN) : void
{
if ($l11n instanceof BaseStringL11n) {
$this->l11n = $l11n;
} elseif (isset($this->l11n) && $this->l11n instanceof BaseStringL11n) {
$this->l11n->content = $l11n;
$this->l11n->setLanguage($lang);
} else {
$this->l11n = new BaseStringL11n();
$this->l11n->content = $l11n;
$this->l11n->setLanguage($lang);
}
}
/**
* @return string
*
* @since 1.0.0
*/
public function getL11n() : string
{
if (!isset($this->l11n)) {
return '';
}
return $this->l11n instanceof BaseStringL11n ? $this->l11n->content : $this->l11n;
}
/**
* {@inheritdoc}
*/
public function toArray() : array
{
return [
'id' => $this->id,
'name' => $this->name,
];
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return $this->toArray();
}
}

View File

@ -0,0 +1,69 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
use phpOMS\Localization\BaseStringL11n;
/**
* mapper class.
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of BaseStringL11n
* @extends DataMapperFactory<T>
*/
final class ExpenseTypeL11nMapper 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 = [
'bizexpenses_expense_type_l11n_id' => ['name' => 'bizexpenses_expense_type_l11n_id', 'type' => 'int', 'internal' => 'id'],
'bizexpenses_expense_type_l11n_title' => ['name' => 'bizexpenses_expense_type_l11n_title', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true],
'bizexpenses_expense_type_l11n_type' => ['name' => 'bizexpenses_expense_type_l11n_type', 'type' => 'int', 'internal' => 'ref'],
'bizexpenses_expense_type_l11n_lang' => ['name' => 'bizexpenses_expense_type_l11n_lang', 'type' => 'string', 'internal' => 'language'],
];
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'bizexpenses_expense_type_l11n';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'bizexpenses_expense_type_l11n_id';
/**
* Model to use by the mapper.
*
* @var class-string<T>
* @since 1.0.0
*/
public const MODEL = BaseStringL11n::class;
}

View File

@ -0,0 +1,82 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/**
* Item mapper class.
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*
* @template T of ExpenseType
* @extends DataMapperFactory<T>
*/
final class ExpenseTypeMapper 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 = [
'bizexpenses_expense_type_id' => ['name' => 'bizexpenses_expense_type_id', 'type' => 'int', 'internal' => 'id'],
'bizexpenses_expense_type_name' => ['name' => 'bizexpenses_expense_type_name', 'type' => 'string', 'internal' => 'name', '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' => ExpenseTypeL11nMapper::class,
'table' => 'bizexpenses_expense_type_l11n',
'self' => 'bizexpenses_expense_type_l11n_type',
'column' => 'content',
'external' => null,
],
];
/**
* Model to use by the mapper.
*
* @var class-string<T>
* @since 1.0.0
*/
public const MODEL = ExpenseType::class;
/**
* Primary table.
*
* @var string
* @since 1.0.0
*/
public const TABLE = 'bizexpenses_expense_type';
/**
* Primary field name.
*
* @var string
* @since 1.0.0
*/
public const PRIMARYFIELD = 'bizexpenses_expense_type_id';
}

46
Models/NullExpense.php Normal file
View File

@ -0,0 +1,46 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
/**
* Null model
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
final class NullExpense extends Expense
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return ['id' => $this->id];
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
/**
* Null model
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
final class NullExpenseElement extends ExpenseElement
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return ['id' => $this->id];
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
/**
* Null model
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
final class NullExpenseElementType extends ExpenseElementType
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return ['id' => $this->id];
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* Karaka
*
* PHP Version 8.1
*
* @package Modules\BusinessExpenses\Models
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\BusinessExpenses\Models;
/**
* Null model
*
* @package Modules\BusinessExpenses\Models
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
final class NullExpenseType extends ExpenseType
{
/**
* Constructor
*
* @param int $id Model id
*
* @since 1.0.0
*/
public function __construct(int $id = 0)
{
$this->id = $id;
}
/**
* {@inheritdoc}
*/
public function jsonSerialize() : mixed
{
return ['id' => $this->id];
}
}

View File

@ -13,4 +13,5 @@
declare(strict_types=1);
return ['Navigation' => [
'BusinessExpenses' => 'Business Expenses',
]];

View File

View File

View File

@ -11,13 +11,14 @@
"phpOMS-db": "1.0.0"
},
"creator": {
"name": "Orange Management",
"website": "www.spl1nes.com"
"name": "Jingga",
"website": "jingga.app"
},
"description": "Accounting module.",
"directory": "BusinessExpenses",
"dependencies": {
"Admin": "1.0.0"
"Admin": "1.0.0",
"Supplier": "1.0.0"
},
"providing": {
"Navigation": "*"