diff --git a/.github/dev_bug_report.md b/.github/dev_bug_report.md new file mode 100755 index 0000000..ef93e56 --- /dev/null +++ b/.github/dev_bug_report.md @@ -0,0 +1,35 @@ +--- +name: Dev Bug Report +about: Create a report to help us improve +title: '' +labels: stat_backlog, type_bug +assignees: '' + +--- + +# Bug Description +A clear and concise description of what the bug is. + +# How to Reproduce + +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +## Minimal Code Example + +``` +// your code ... +``` + +# Expected Behavior +A clear and concise description of what you expected to happen. + +# Screenshots +If applicable, add screenshots to help explain your problem. + +# Additional Information +Add any other context about the problem here. diff --git a/.github/dev_feature_request.md b/.github/dev_feature_request.md new file mode 100755 index 0000000..9573c35 --- /dev/null +++ b/.github/dev_feature_request.md @@ -0,0 +1,18 @@ +--- +name: Dev Feature Request +about: Suggest an idea for this project +title: '' +labels: stat_backlog, type_feature +assignees: '' + +--- + +# What is the feature you request +* A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] +* A clear and concise description of what you want to happen. + +# Alternatives +A clear and concise description of any alternative solutions or features you've considered. + +# Additional Information +Add any other context or screenshots about the feature request here. diff --git a/.github/user_bug_report.md b/.github/user_bug_report.md new file mode 100755 index 0000000..df09513 --- /dev/null +++ b/.github/user_bug_report.md @@ -0,0 +1,34 @@ +--- +name: User Bug Report +about: Create a report to help us improve +title: '' +labels: stat_backlog, type_bug +assignees: '' + +--- + +# Bug Description +A clear and concise description of what the bug is. + +# How to Reproduce +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +# Expected Behavior +A clear and concise description of what you expected to happen. + +# Screenshots +If applicable, add screenshots to help explain your problem. + +# System Information + - System: [e.g. PC or iPhone11, ...] + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Orange Management Version [e.g. 22] + +# Additional Information +Add any other context about the problem here. diff --git a/.github/user_feature_request.md b/.github/user_feature_request.md new file mode 100755 index 0000000..6eb8ddc --- /dev/null +++ b/.github/user_feature_request.md @@ -0,0 +1,18 @@ +--- +name: User Feature Request +about: Suggest an idea for this project +title: '' +labels: stat_backlog, type_feature +assignees: '' + +--- + +# What is the feature you request +* A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] +* A clear and concise description of what you want to happen. + +# Alternatives +A clear and concise description of any alternative solutions or features you've considered. + +# Additional Information +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml new file mode 100755 index 0000000..adb8716 --- /dev/null +++ b/.github/workflows/greetings.yml @@ -0,0 +1,13 @@ +name: Greetings + +on: [pull_request, issues] + +jobs: + greeting: + runs-on: ubuntu-latest + steps: + - uses: actions/first-interaction@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + issue-message: 'Thank you for createing this issue. We will check it as soon as possible.' + pr-message: 'Thank you for your pull request. We will check it as soon as possible.' diff --git a/.github/workflows/image.yml b/.github/workflows/image.yml new file mode 100755 index 0000000..d2fb2d4 --- /dev/null +++ b/.github/workflows/image.yml @@ -0,0 +1,24 @@ +name: Compress images +on: + push: + paths: + - '**.jpg' + - '**.png' + - '**.webp' + pull_request: + paths: + - '**.jpg' + - '**.png' + - '**.webp' +jobs: + build: + name: calibreapp/image-actions + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@master + + - name: Compress Images + uses: calibreapp/image-actions@master + with: + githubToken: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100755 index 0000000..4bc97f2 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,118 @@ +name: CI/CD + +on: [push] + +jobs: + autoformat: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, 'NO_CI')" + strategy: + fail-fast: false + max-parallel: 3 + steps: + - name: Checkout Repository + uses: actions/checkout@master + with: + fetch-depth: 1 + - name: Get Composer Cache Directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Cache dependencies + uses: actions/cache@v1 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + - name: Setup Composer + run: composer install + - name: Autoformat + run: 'vendor/bin/php-cs-fixer fix ./ --rules=''{"array_syntax": {"syntax": "short"}, "blank_line_after_namespace": true, "cast_spaces": {"space": "single"}, "combine_consecutive_issets": true, "compact_nullable_typehint": true, "declare_strict_types": true, "elseif": true, "encoding": true, "explicit_indirect_variable": true, "explicit_string_variable": true, "function_to_constant": true, "implode_call": true, "increment_style": {"style": "pre"}, "is_null": {"use_yoda_style": false}, "line_ending": true, "logical_operators": true, "lowercase_cast": true, "lowercase_constants": true, "lowercase_keywords": true, "modernize_types_casting": true, "native_constant_invocation": true, "native_function_casing": true, "native_function_invocation": true, "new_with_braces": true, "no_alias_functions": true, "no_closing_tag": true, "no_empty_comment": true, "no_empty_phpdoc": true, "no_empty_statement": true, "no_homoglyph_names": true, "no_mixed_echo_print": {"use": "echo"}, "no_php4_constructor": true, "no_singleline_whitespace_before_semicolons": true, "no_spaces_inside_parenthesis": true, "no_trailing_whitespace": true, "no_unneeded_final_method": true, "no_unused_imports": true, "no_useless_return": true, "no_whitespace_before_comma_in_array": true, "no_whitespace_in_blank_line": true, "non_printable_character": true, "ordered_imports": {"sort_algorithm": "alpha"}, "php_unit_construct": true, "php_unit_internal_class": true, "php_unit_ordered_covers": true, "php_unit_set_up_tear_down_visibility": true, "phpdoc_align": {"align": "vertical"}, "phpdoc_annotation_without_dot": true, "phpdoc_scalar": true, "phpdoc_trim_consecutive_blank_line_separation": true, "random_api_migration": true, "self_accessor": true, "set_type_to_cast": true, "short_scalar_cast": true, "single_blank_line_at_eof": true, "single_line_after_imports": true, "standardize_increment": true, "trailing_comma_in_multiline_array": true, "trim_array_spaces": true, "visibility_required": true, "void_return": true}'' --allow-risky=yes' + - name: Check for modified files + id: git-check + run: echo ::set-output name=modified::$(if git diff-index --quiet HEAD --; then echo "false"; else echo "true"; fi) + - name: Push changes + if: steps.git-check.outputs.modified == 'true' + run: | + git config --global user.name 'Formatter Bot' + git config --global user.email 'formatter.bot@orange-management.email' + git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }} + git commit -am "Automated formatting changes" + git push + codestyle-tests: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, 'NO_CI')" + strategy: + fail-fast: false + max-parallel: 3 + matrix: + php-versions: ['7.4'] + steps: + - name: Checkout Repository + uses: actions/checkout@master + with: + fetch-depth: 1 + - name: Checkout Build Repository + uses: actions/checkout@master + with: + fetch-depth: 1 + ref: develop + repository: Orange-Management/Build + path: Build + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@master + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, gd, zip, dom, mysql, pgsql, sqlite, imap, bcmath, redis, memcached + ini-values: opcache.jit_buffer_size=256M, opcache.jit=1235, pcre.jit=1 + - name: Get Composer Cache Directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Cache dependencies + uses: actions/cache@v1 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + - name: Setup Composer + run: composer install + - name: phpcs + run: vendor/bin/phpcs ./ --standard="Build/Config/phpcs.xml" -s --report=full + custom: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, 'NO_CI')" + strategy: + fail-fast: false + max-parallel: 3 + matrix: + php-versions: ['7.4', '8.0'] + steps: + - name: Checkout Repository + uses: actions/checkout@master + with: + fetch-depth: 1 + - name: Checkout Build Repository + uses: actions/checkout@master + with: + fetch-depth: 1 + ref: develop + repository: Orange-Management/Build + path: Build + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@master + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, gd, zip, dom, mysql, pgsql, sqlite, imap, bcmath, redis, memcached + ini-values: opcache.jit_buffer_size=256M, opcache.jit=1235, pcre.jit=1 + - name: PHP linting + run: find ./ -type f -name '*.php' -print0 | xargs -0 -n1 -P4 php -l -n | (! grep -v "No syntax errors detected" ) + - name: Php strict + run: if [[ $(grep -r -L "declare(strict_types=1);" --include=*.php --exclude={*.tpl.php,*Hooks.php,*Routes.php,*SearchCommands.php} ./) -ne "" ]]; then exit 1; fi + - name: Html inspection + run: | + if [[ $(find ./ -name "*tpl.php" | xargs grep -E '=\"[\#\$\%\^\&\*\(\)\\/\ ]*\"') -ne "" ]]; then exit 1; fi + if [[ $(find ./ -name "*tpl.php" | xargs grep -P '(\)') -ne "" ]]; then exit 1; fi + - name: Js strict + run: if [[ $(grep -r -L "\"use strict\";" --include=*.js ./) -ne "" ]]; then exit 1; fi + - name: Js inspection + run: | + if [[ $(grep -rlni "onafterprint=\|onbeforeprint=\|onbeforeunload=\|onerror=\|onhaschange=\|onload=\|onmessage=\|onoffline=\|ononline=\|onpagehide=\|onpageshow=\|onpopstate=\|onredo=\|onresize=\|onstorage=\|onund=o\|onunload=\|onblur=\|onchage=\|oncontextmenu=\|onfocus=\|onformchange=\|onforminput=\|oninput=\|oninvalid=\|onreset=\|onselect=\|onsubmit=\|onkeydown=\|onkeypress=\|onkeyup=\|onclick=\|ondblclic=k\|ondrag=\|ondragend=\|ondragenter=\|ondragleave=\|ondragover=\|ondragstart=\|ondrop=\|onmousedown=\|onmousemove=\|onmouseout=\|onmouseover=\|onmouseup=\|onmousewheel=\|onscroll=\|onabor=t\|oncanplay=\|oncanplaythrough=\|ondurationchange=\|onemptied=\|onended=\|onerror=\|onloadeddata=\|onloadedmetadata=\|onloadstart=\|onpause=\|onplay=\|onplaying=\|onprogress=\|onratechange=\|onreadystatechange=\|onseeked=\|onseeking=\|onstalled=\|onsuspend=\|ontimeupdate=\|onvolumechange=" --include=*.js ./) -ne "" ]]; then exit 1; fi diff --git a/Admin/Install/Navigation.install.json b/Admin/Install/Navigation.install.json index 1a003fc..9b7b2d5 100644 --- a/Admin/Install/Navigation.install.json +++ b/Admin/Install/Navigation.install.json @@ -18,8 +18,8 @@ "pid": "/", "type": 2, "subtype": 1, - "name": "Accounts", - "uri": "{/prefix}accounting/gl/list", + "name": "CostCenters", + "uri": "{/prefix}accounting/costcenter/list", "target": "self", "icon": null, "order": 5, @@ -33,7 +33,7 @@ "type": 3, "subtype": 1, "name": "List", - "uri": "{/prefix}accounting/gl/list", + "uri": "{/prefix}accounting/costcenter/list", "target": "self", "icon": null, "order": 1, @@ -48,7 +48,7 @@ "type": 3, "subtype": 1, "name": "Create", - "uri": "{/prefix}accounting/gl/create?{?}", + "uri": "{/prefix}accounting/costcenter/create?{?}", "target": "self", "icon": null, "order": 5, @@ -59,6 +59,98 @@ } ] }, + { + "id": 1002603001, + "pid": "/", + "type": 2, + "subtype": 1, + "name": "CostObjects", + "uri": "{/prefix}accounting/costobject/list", + "target": "self", + "icon": null, + "order": 5, + "from": "Accounting", + "permission": { "permission": 2, "type": null, "element": null }, + "parent": 1002601001, + "children": [ + { + "id": 1002603101, + "pid": "/accounting", + "type": 3, + "subtype": 1, + "name": "List", + "uri": "{/prefix}accounting/costobject/list", + "target": "self", + "icon": null, + "order": 1, + "from": "Accounting", + "permission": { "permission": 2, "type": null, "element": null }, + "parent": 1002603001, + "children": [] + }, + { + "id": 1002603201, + "pid": "/accounting", + "type": 3, + "subtype": 1, + "name": "Create", + "uri": "{/prefix}accounting/costobject/create?{?}", + "target": "self", + "icon": null, + "order": 5, + "from": "Accounting", + "permission": { "permission": 4, "type": null, "element": null }, + "parent": 1002603001, + "children": [] + } + ] + }, + { + "id": 1002604001, + "pid": "/", + "type": 2, + "subtype": 1, + "name": "Accounts", + "uri": "{/prefix}accounting/gl/list", + "target": "self", + "icon": null, + "order": 5, + "from": "Accounting", + "permission": { "permission": 2, "type": null, "element": null }, + "parent": 1002601001, + "children": [ + { + "id": 1002604101, + "pid": "/accounting", + "type": 3, + "subtype": 1, + "name": "List", + "uri": "{/prefix}accounting/gl/list", + "target": "self", + "icon": null, + "order": 1, + "from": "Accounting", + "permission": { "permission": 2, "type": null, "element": null }, + "parent": 1002604001, + "children": [] + }, + { + "id": 1002604201, + "pid": "/accounting", + "type": 3, + "subtype": 1, + "name": "Create", + "uri": "{/prefix}accounting/gl/create?{?}", + "target": "self", + "icon": null, + "order": 5, + "from": "Accounting", + "permission": { "permission": 4, "type": null, "element": null }, + "parent": 1002604001, + "children": [] + } + ] + }, { "id": 1002605001, "pid": "/", diff --git a/Admin/Install/db.json b/Admin/Install/db.json index 18af3dd..7e25957 100644 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -32,6 +32,129 @@ } } }, + + "accounting_costcenter": { + "name": "accounting_costcenter", + "fields": { + "accounting_costcenter_id": { + "name": "accounting_costcenter_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "accounting_costcenter_code": { + "name": "accounting_costcenter_code", + "type": "VARCHAR(255)", + "null": false + }, + "accounting_costcenter_parent": { + "name": "accounting_costcenter_parent", + "type": "INT", + "default": null, + "null": true + } + } + }, + "accounting_costcenter_l11n": { + "name": "accounting_costcenter_l11n", + "fields": { + "accounting_costcenter_l11n_id": { + "name": "accounting_costcenter_l11n_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "accounting_costcenter_l11n_name": { + "name": "accounting_costcenter_l11n_name", + "type": "VARCHAR(255)", + "null": false + }, + "accounting_costcenter_l11n_description": { + "name": "accounting_costcenter_l11n_description", + "type": "VARCHAR(255)", + "null": false + }, + "accounting_costcenter_l11n_costcenter": { + "name": "accounting_costcenter_l11n_costcenter", + "type": "INT", + "null": false, + "foreignTable": "accounting_costcenter", + "foreignKey": "accounting_costcenter_id" + }, + "accounting_costcenter_l11n_language": { + "name": "accounting_costcenter_l11n_language", + "type": "VARCHAR(2)", + "default": null, + "null": true, + "foreignTable": "language", + "foreignKey": "language_639_1" + } + } + }, + + "accounting_costobject": { + "name": "accounting_costobject", + "fields": { + "accounting_costobject_id": { + "name": "accounting_costobject_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "accounting_costobject_code": { + "name": "accounting_costobject_code", + "type": "VARCHAR(255)", + "null": false + }, + "accounting_costobject_parent": { + "name": "accounting_costobject_parent", + "type": "INT", + "default": null, + "null": true + } + } + }, + "accounting_costobject_l11n": { + "name": "accounting_costobject_l11n", + "fields": { + "accounting_costobject_l11n_id": { + "name": "accounting_costobject_l11n_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "accounting_costobject_l11n_name": { + "name": "accounting_costobject_l11n_name", + "type": "VARCHAR(255)", + "null": false + }, + "accounting_costobject_l11n_description": { + "name": "accounting_costobject_l11n_description", + "type": "VARCHAR(255)", + "null": false + }, + "accounting_costobject_l11n_costobject": { + "name": "accounting_costobject_l11n_costobject", + "type": "INT", + "null": false, + "foreignTable": "accounting_costobject", + "foreignKey": "accounting_costobject_id" + }, + "accounting_costobject_l11n_language": { + "name": "accounting_costobject_l11n_language", + "type": "VARCHAR(2)", + "default": null, + "null": true, + "foreignTable": "language", + "foreignKey": "language_639_1" + } + } + }, + "accounting_batch": { "name": "accounting_batch", "fields": { diff --git a/Admin/Routes/Web/Backend.php b/Admin/Routes/Web/Backend.php index a59e28a..560af9e 100644 --- a/Admin/Routes/Web/Backend.php +++ b/Admin/Routes/Web/Backend.php @@ -182,4 +182,27 @@ return [ ], ], ], + + '^.*/accounting/costcenter/list.*$' => [ + [ + 'dest' => '\Modules\Accounting\Controller\BackendController:viewCostCenterList', + 'verb' => RouteVerb::GET, + 'permission' => [ + 'module' => BackendController::MODULE_NAME, + 'type' => PermissionType::READ, + 'state' => PermissionState::COST_CENTER, + ], + ], + ], + '^.*/accounting/costobject/list.*$' => [ + [ + 'dest' => '\Modules\Accounting\Controller\BackendController:viewCostObjectList', + 'verb' => RouteVerb::GET, + 'permission' => [ + 'module' => BackendController::MODULE_NAME, + 'type' => PermissionType::READ, + 'state' => PermissionState::COST_OBJECT, + ], + ], + ], ]; diff --git a/Controller/BackendController.php b/Controller/BackendController.php index cc14579..c2195a7 100644 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -14,6 +14,8 @@ declare(strict_types=1); namespace Modules\Accounting\Controller; +use Modules\Accounting\Models\CostCenterMapper; +use Modules\Accounting\Models\CostObjectMapper; use phpOMS\Contract\RenderableInterface; use phpOMS\Message\RequestAbstract; use phpOMS\Message\ResponseAbstract; @@ -192,7 +194,7 @@ final class BackendController extends Controller { $view = new View($this->app->l11nManager, $request, $response); $view->setTemplate('/Modules/Accounting/Theme/Backend/gl-list'); - $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1002602001, $request, $response)); + $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1002604001, $request, $response)); return $view; } @@ -213,7 +215,7 @@ final class BackendController extends Controller { $view = new View($this->app->l11nManager, $request, $response); $view->setTemplate('/Modules/Accounting/Theme/Backend/gl-create'); - $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1002602001, $request, $response)); + $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1002604001, $request, $response)); return $view; } @@ -234,8 +236,84 @@ final class BackendController extends Controller { $view = new View($this->app->l11nManager, $request, $response); $view->setTemplate('/Modules/Accounting/Theme/Backend/gl-profile'); + $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1002604001, $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 + * + * @since 1.0.0 + * @codeCoverageIgnore + */ + public function viewCostCenterList(RequestAbstract $request, ResponseAbstract $response, $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + $view->setTemplate('/Modules/Accounting/Theme/Backend/costcenter-list'); $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1002602001, $request, $response)); + if ($request->getData('ptype') === '-') { + $view->setData('costcenter', + CostCenterMapper::withConditional('language', $response->getHeader()->getL11n()->getLanguage()) + ::getBeforePivot((int) ($request->getData('id') ?? 0), null, 25) + ); + } elseif ($request->getData('ptype') === '+') { + $view->setData('costcenter', + CostCenterMapper::withConditional('language', $response->getHeader()->getL11n()->getLanguage()) + ::getAfterPivot((int) ($request->getData('id') ?? 0), null, 25) + ); + } else { + $view->setData('costcenter', + CostCenterMapper::withConditional('language', $response->getHeader()->getL11n()->getLanguage()) + ::getAfterPivot(0, null, 25) + ); + } + + return $view; + } + + /** + * Routing end-point for application behaviour. + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return RenderableInterface + * + * @since 1.0.0 + * @codeCoverageIgnore + */ + public function viewCostObjectList(RequestAbstract $request, ResponseAbstract $response, $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + $view->setTemplate('/Modules/Accounting/Theme/Backend/costobject-list'); + $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1002603001, $request, $response)); + + if ($request->getData('ptype') === '-') { + $view->setData('costobject', + CostObjectMapper::withConditional('language', $response->getHeader()->getL11n()->getLanguage()) + ::getBeforePivot((int) ($request->getData('id') ?? 0), null, 25) + ); + } elseif ($request->getData('ptype') === '+') { + $view->setData('costobject', + CostObjectMapper::withConditional('language', $response->getHeader()->getL11n()->getLanguage()) + ::getAfterPivot((int) ($request->getData('id') ?? 0), null, 25) + ); + } else { + $view->setData('costobject', + CostObjectMapper::withConditional('language', $response->getHeader()->getL11n()->getLanguage()) + ::getAfterPivot(0, null, 25) + ); + } + return $view; } } diff --git a/Models/CostCenter.php b/Models/CostCenter.php new file mode 100644 index 0000000..d357cb4 --- /dev/null +++ b/Models/CostCenter.php @@ -0,0 +1,184 @@ +l11n = new L11nCostCenter(); + } + + /** + * Get balance id + * + * @return int + * + * @since 1.0.0 + */ + public function getId() : int + { + return $this->id; + } + + /** + * Set code + * + * @param string $code Balance code + * + * @return void + * + * @since 1.0.0 + */ + public function setCode(string $code) : void + { + $this->code = $code; + } + + /** + * Get code + * + * @return string + * + * @since 1.0.0 + */ + public function getCode() : string + { + return $this->code; + } + + /** + * Set name + * + * @param string $name Balance name + * + * @return void + * + * @since 1.0.0 + */ + public function setName(string $name) : void + { + $this->l11n->setName($name); + } + + /** + * Get name + * + * @return string + * + * @since 1.0.0 + */ + public function getName() : string + { + return $this->l11n->getName(); + } + + /** + * Set description + * + * @param string $description Balance description + * + * @return void + * + * @since 1.0.0 + */ + public function setDescription(string $description) : void + { + $this->l11n->setDescription($description); + } + + /** + * Get description + * + * @return string + * + * @since 1.0.0 + */ + public function getDescription() : string + { + return $this->l11n->getDescription(); + } + + /** + * Set parent + * + * @param string $parent Parent + * + * @return void + * + * @since 1.0.0 + */ + public function setParent($parent) : void + { + $this->parent = $parent; + } + + /** + * Get parent + * + * @return mixed + * + * @since 1.0.0 + */ + public function getParent() + { + return $this->parent; + } +} diff --git a/Models/CostCenterMapper.php b/Models/CostCenterMapper.php new file mode 100644 index 0000000..e54b358 --- /dev/null +++ b/Models/CostCenterMapper.php @@ -0,0 +1,79 @@ + + * @since 1.0.0 + */ + protected static array $columns = [ + 'accounting_costcenter_id' => ['name' => 'accounting_costcenter_id', 'type' => 'int', 'internal' => 'id'], + 'accounting_costcenter_code' => ['name' => 'accounting_costcenter_code', 'type' => 'string', 'internal' => 'code'], + ]; + + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + protected static array $hasMany = [ + 'l11n' => [ + 'mapper' => L11nCostCenterMapper::class, + 'table' => 'accounting_costcenter_l11n', + 'external' => 'accounting_costcenter_l11n_costcenter', + 'conditional' => true, + 'self' => null, + ], + ]; + + /** + * Model to use by the mapper. + * + * @var string + * @since 1.0.0 + */ + protected static string $model = CostCenter::class; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + protected static string $table = 'accounting_costcenter'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + protected static string $primaryField = 'accounting_costcenter_id'; +} diff --git a/Models/CostObject.php b/Models/CostObject.php new file mode 100644 index 0000000..1308f7b --- /dev/null +++ b/Models/CostObject.php @@ -0,0 +1,184 @@ +l11n = new L11nCostObject(); + } + + /** + * Get balance id + * + * @return int + * + * @since 1.0.0 + */ + public function getId() : int + { + return $this->id; + } + + /** + * Set code + * + * @param string $code Balance code + * + * @return void + * + * @since 1.0.0 + */ + public function setCode(string $code) : void + { + $this->code = $code; + } + + /** + * Get code + * + * @return string + * + * @since 1.0.0 + */ + public function getCode() : string + { + return $this->code; + } + + /** + * Set name + * + * @param string $name Balance name + * + * @return void + * + * @since 1.0.0 + */ + public function setName(string $name) : void + { + $this->l11n->setName($name); + } + + /** + * Get name + * + * @return string + * + * @since 1.0.0 + */ + public function getName() : string + { + return $this->l11n->getName(); + } + + /** + * Set description + * + * @param string $description Balance description + * + * @return void + * + * @since 1.0.0 + */ + public function setDescription(string $description) : void + { + $this->l11n->setDescription($description); + } + + /** + * Get description + * + * @return string + * + * @since 1.0.0 + */ + public function getDescription() : string + { + return $this->l11n->getDescription(); + } + + /** + * Set parent + * + * @param string $parent Parent + * + * @return void + * + * @since 1.0.0 + */ + public function setParent($parent) : void + { + $this->parent = $parent; + } + + /** + * Get parent + * + * @return mixed + * + * @since 1.0.0 + */ + public function getParent() + { + return $this->parent; + } +} diff --git a/Models/CostObjectMapper.php b/Models/CostObjectMapper.php new file mode 100644 index 0000000..4c849d4 --- /dev/null +++ b/Models/CostObjectMapper.php @@ -0,0 +1,79 @@ + + * @since 1.0.0 + */ + protected static array $columns = [ + 'accounting_costobject_id' => ['name' => 'accounting_costobject_id', 'type' => 'int', 'internal' => 'id'], + 'accounting_costobject_code' => ['name' => 'accounting_costobject_code', 'type' => 'string', 'internal' => 'code'], + ]; + + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + protected static array $hasMany = [ + 'l11n' => [ + 'mapper' => L11nCostObjectMapper::class, + 'table' => 'accounting_costobject_l11n', + 'external' => 'accounting_costobject_l11n_costobject', + 'conditional' => true, + 'self' => null, + ], + ]; + + /** + * Model to use by the mapper. + * + * @var string + * @since 1.0.0 + */ + protected static string $model = CostObject::class; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + protected static string $table = 'accounting_costobject'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + protected static string $primaryField = 'accounting_costobject_id'; +} diff --git a/Models/L11nCostCenter.php b/Models/L11nCostCenter.php new file mode 100644 index 0000000..9d11417 --- /dev/null +++ b/Models/L11nCostCenter.php @@ -0,0 +1,206 @@ +id; + } + + /** + * Set costcenter. + * + * @param int $costcenter CostCenter id + * + * @return void + * + * @since 1.0.0 + */ + public function setCostCenter(int $costcenter) : void + { + $this->costcenter = $costcenter; + } + + /** + * Get costcenter + * + * @return int + * + * @since 1.0.0 + */ + public function getCostCenter() : int + { + return $this->costcenter; + } + + /** + * Get language + * + * @return string + * + * @since 1.0.0 + */ + public function getLanguage() : string + { + return $this->language; + } + + /** + * Set language + * + * @param string $language Language + * + * @return void + * + * @since 1.0.0 + */ + public function setLanguage(string $language) : void + { + $this->language = $language; + } + + /** + * Get costcenter name. + * + * @return string + * + * @since 1.0.0 + */ + public function getName() : string + { + return $this->name; + } + + /** + * Set name + * + * @param string $name Name + * + * @return void + * + * @since 1.0.0 + */ + public function setName(string $name) : void + { + $this->name = $name; + } + + /** + * Get costcenter description. + * + * @return string + * + * @since 1.0.0 + */ + public function getDescription() : string + { + return $this->description; + } + + /** + * Set description + * + * @param string $description Description + * + * @return void + * + * @since 1.0.0 + */ + public function setDescription(string $description) : void + { + $this->description = $description; + } + + /** + * {@inheritdoc} + */ + public function toArray() : array + { + return [ + 'id' => $this->id, + 'name' => $this->name, + 'costcenter' => $this->costcenter, + 'language' => $this->language, + ]; + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() + { + return $this->toArray(); + } +} diff --git a/Models/L11nCostCenterMapper.php b/Models/L11nCostCenterMapper.php new file mode 100644 index 0000000..1c58da1 --- /dev/null +++ b/Models/L11nCostCenterMapper.php @@ -0,0 +1,77 @@ + + * @since 1.0.0 + */ + protected static array $columns = [ + 'accounting_costcenter_l11n_id' => ['name' => 'accounting_costcenter_l11n_id', 'type' => 'int', 'internal' => 'id'], + 'accounting_costcenter_l11n_name' => ['name' => 'accounting_costcenter_l11n_name', 'type' => 'string', 'internal' => 'name', 'autocomplete' => true], + 'accounting_costcenter_l11n_description' => ['name' => 'accounting_costcenter_l11n_description', 'type' => 'string', 'internal' => 'description', 'autocomplete' => true], + 'accounting_costcenter_l11n_costcenter' => ['name' => 'accounting_costcenter_l11n_costcenter', 'type' => 'int', 'internal' => 'costcenter'], + 'accounting_costcenter_l11n_language' => ['name' => 'accounting_costcenter_l11n_language', 'type' => 'string', 'internal' => 'language'], + ]; + + /** + * Has one relation. + * + * @var array + * @since 1.0.0 + */ + protected static array $ownsOne = [ + 'language' => [ + 'mapper' => LanguageMapper::class, + 'self' => 'accounting_costcenter_l11n_language', + 'by' => 'code2', + 'column' => 'code2', + 'conditional' => true, + ], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + protected static string $table = 'accounting_costcenter_l11n'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + protected static string $primaryField = 'accounting_costcenter_l11n_id'; +} diff --git a/Models/L11nCostObject.php b/Models/L11nCostObject.php new file mode 100644 index 0000000..e13cd10 --- /dev/null +++ b/Models/L11nCostObject.php @@ -0,0 +1,206 @@ +id; + } + + /** + * Set costobject. + * + * @param int $costobject CostObject id + * + * @return void + * + * @since 1.0.0 + */ + public function setCostObject(int $costobject) : void + { + $this->costobject = $costobject; + } + + /** + * Get costobject + * + * @return int + * + * @since 1.0.0 + */ + public function getCostObject() : int + { + return $this->costobject; + } + + /** + * Get language + * + * @return string + * + * @since 1.0.0 + */ + public function getLanguage() : string + { + return $this->language; + } + + /** + * Set language + * + * @param string $language Language + * + * @return void + * + * @since 1.0.0 + */ + public function setLanguage(string $language) : void + { + $this->language = $language; + } + + /** + * Get costobject name. + * + * @return string + * + * @since 1.0.0 + */ + public function getName() : string + { + return $this->name; + } + + /** + * Set name + * + * @param string $name Name + * + * @return void + * + * @since 1.0.0 + */ + public function setName(string $name) : void + { + $this->name = $name; + } + + /** + * Get costobject description. + * + * @return string + * + * @since 1.0.0 + */ + public function getDescription() : string + { + return $this->description; + } + + /** + * Set description + * + * @param string $description Description + * + * @return void + * + * @since 1.0.0 + */ + public function setDescription(string $description) : void + { + $this->description = $description; + } + + /** + * {@inheritdoc} + */ + public function toArray() : array + { + return [ + 'id' => $this->id, + 'name' => $this->name, + 'costobject' => $this->costobject, + 'language' => $this->language, + ]; + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() + { + return $this->toArray(); + } +} diff --git a/Models/L11nCostObjectMapper.php b/Models/L11nCostObjectMapper.php new file mode 100644 index 0000000..d242062 --- /dev/null +++ b/Models/L11nCostObjectMapper.php @@ -0,0 +1,77 @@ + + * @since 1.0.0 + */ + protected static array $columns = [ + 'accounting_costobject_l11n_id' => ['name' => 'accounting_costobject_l11n_id', 'type' => 'int', 'internal' => 'id'], + 'accounting_costobject_l11n_name' => ['name' => 'accounting_costobject_l11n_name', 'type' => 'string', 'internal' => 'name', 'autocomplete' => true], + 'accounting_costobject_l11n_description' => ['name' => 'accounting_costobject_l11n_description', 'type' => 'string', 'internal' => 'description', 'autocomplete' => true], + 'accounting_costobject_l11n_costobject' => ['name' => 'accounting_costobject_l11n_costobject', 'type' => 'int', 'internal' => 'costobject'], + 'accounting_costobject_l11n_language' => ['name' => 'accounting_costobject_l11n_language', 'type' => 'string', 'internal' => 'language'], + ]; + + /** + * Has one relation. + * + * @var array + * @since 1.0.0 + */ + protected static array $ownsOne = [ + 'language' => [ + 'mapper' => LanguageMapper::class, + 'self' => 'accounting_costobject_l11n_language', + 'by' => 'code2', + 'column' => 'code2', + 'conditional' => true, + ], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + protected static string $table = 'accounting_costobject_l11n'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + protected static string $primaryField = 'accounting_costobject_l11n_id'; +} diff --git a/Models/NullCostCenter.php b/Models/NullCostCenter.php new file mode 100644 index 0000000..cd57d8c --- /dev/null +++ b/Models/NullCostCenter.php @@ -0,0 +1,38 @@ +id = $id; + } +} diff --git a/Models/NullCostObject.php b/Models/NullCostObject.php new file mode 100644 index 0000000..c574e5c --- /dev/null +++ b/Models/NullCostObject.php @@ -0,0 +1,38 @@ +id = $id; + } +} diff --git a/Models/PermissionState.php b/Models/PermissionState.php index fd0f342..81f60ff 100644 --- a/Models/PermissionState.php +++ b/Models/PermissionState.php @@ -32,6 +32,7 @@ abstract class PermissionState extends Enum public const STACK = 4; public const GL = 5; public const COST_CENTER = 6; - public const ACCOUNT = 7; - public const ENTRY = 8; + public const COST_OBJECT = 7; + public const ACCOUNT = 8; + public const ENTRY = 9; } diff --git a/Theme/Backend/costcenter-list.tpl.php b/Theme/Backend/costcenter-list.tpl.php new file mode 100644 index 0000000..82cf54c --- /dev/null +++ b/Theme/Backend/costcenter-list.tpl.php @@ -0,0 +1,52 @@ +getData('costcenter'); + +$previous = empty($costcenter) ? '{/prefix}tag/list' : '{/prefix}tag/list?{?}&id=' . \reset($costcenter)->getId() . '&ptype=-'; +$next = empty($costcenter) ? '{/prefix}tag/list' : '{/prefix}tag/list?{?}&id=' . \end($costcenter)->getId() . '&ptype=+'; + +echo $this->getData('nav')->render(); ?> +
+
+
+
getHtml('CostCenters') ?>
+ + + + + $value) : ++$count; + $url = UriFactory::build('{/prefix}tag/single?{?}&id=' . $value->getId()); ?> + +
getHtml('Code') ?> + getHtml('Name') ?> +
printHtml($value->getCode()); ?> + printHtml($value->getName()); ?> + + +
getHtml('Empty', '0', '0'); ?> + +
+ +
+
diff --git a/Theme/Backend/costobject-list.tpl.php b/Theme/Backend/costobject-list.tpl.php new file mode 100644 index 0000000..a227552 --- /dev/null +++ b/Theme/Backend/costobject-list.tpl.php @@ -0,0 +1,52 @@ +getData('costobject'); + +$previous = empty($costobject) ? '{/prefix}tag/list' : '{/prefix}tag/list?{?}&id=' . \reset($costobject)->getId() . '&ptype=-'; +$next = empty($costobject) ? '{/prefix}tag/list' : '{/prefix}tag/list?{?}&id=' . \end($costobject)->getId() . '&ptype=+'; + +echo $this->getData('nav')->render(); ?> +
+
+
+
getHtml('CostObjects') ?>
+ + + + + $value) : ++$count; + $url = UriFactory::build('{/prefix}tag/single?{?}&id=' . $value->getId()); ?> + +
getHtml('Code') ?> + getHtml('Name') ?> +
printHtml($value->getCode()); ?> + printHtml($value->getName()); ?> + + +
getHtml('Empty', '0', '0'); ?> + +
+ +
+
diff --git a/tests/Admin/AdminTest.php b/tests/Admin/AdminTest.php new file mode 100644 index 0000000..2d57366 --- /dev/null +++ b/tests/Admin/AdminTest.php @@ -0,0 +1,26 @@ +setCode('123'); + $costcenter->setName('Test CostCenter'); + $costcenter->setDescription('Test description'); + + $id = CostCenterMapper::create($costcenter); + self::assertGreaterThan(0, $costcenter->getId()); + self::assertEquals($id, $costcenter->getId()); + + $costcenterR = CostCenterMapper::withConditional('language', ISO639x1Enum::_EN)::get($costcenter->getId()); + self::assertEquals($costcenter->getCode(), $costcenterR->getCode()); + self::assertEquals($costcenter->getName(), $costcenterR->getName()); + self::assertEquals($costcenter->getDescription(), $costcenterR->getDescription()); + } +} diff --git a/tests/Models/CostCenterTest.php b/tests/Models/CostCenterTest.php new file mode 100644 index 0000000..5db274c --- /dev/null +++ b/tests/Models/CostCenterTest.php @@ -0,0 +1,66 @@ +getId()); + self::assertEquals('', $cc->getName()); + self::assertEquals('', $cc->getCode()); + self::assertEquals('', $cc->getDescription()); + self::assertEquals(null, $cc->getParent()); + } + + public function testNameInputOutput() : void + { + $cc = new CostCenter(); + + $cc->setName('TestName'); + self::assertEquals('TestName', $cc->getName()); + } + + public function testCodeInputOutput() : void + { + $cc = new CostCenter(); + + $cc->setCode('TestCode'); + self::assertEquals('TestCode', $cc->getCode()); + } + + public function testDescriptionInputOutput() : void + { + $cc = new CostCenter(); + + $cc->setDescription('TestDescription'); + self::assertEquals('TestDescription', $cc->getDescription()); + } + + public function testParentInputOutput() : void + { + $cc = new CostCenter(); + + $cc->setParent(1); + self::assertEquals(1, $cc->getParent()); + } +} diff --git a/tests/Models/CostObjectMapperTest.php b/tests/Models/CostObjectMapperTest.php new file mode 100644 index 0000000..7e5361d --- /dev/null +++ b/tests/Models/CostObjectMapperTest.php @@ -0,0 +1,42 @@ +setCode('123'); + $costobject->setName('Test CostObject'); + $costobject->setDescription('Test description'); + + $id = CostObjectMapper::create($costobject); + self::assertGreaterThan(0, $costobject->getId()); + self::assertEquals($id, $costobject->getId()); + + $costobjectR = CostObjectMapper::withConditional('language', ISO639x1Enum::_EN)::get($costobject->getId()); + self::assertEquals($costobject->getCode(), $costobjectR->getCode()); + self::assertEquals($costobject->getName(), $costobjectR->getName()); + self::assertEquals($costobject->getDescription(), $costobjectR->getDescription()); + } +} diff --git a/tests/Models/CostObjectTest.php b/tests/Models/CostObjectTest.php new file mode 100644 index 0000000..10e3af6 --- /dev/null +++ b/tests/Models/CostObjectTest.php @@ -0,0 +1,66 @@ +getId()); + self::assertEquals('', $co->getName()); + self::assertEquals('', $co->getCode()); + self::assertEquals('', $co->getDescription()); + self::assertEquals(null, $co->getParent()); + } + + public function testNameInputOutput() : void + { + $co = new CostObject(); + + $co->setName('TestName'); + self::assertEquals('TestName', $co->getName()); + } + + public function testCodeInputOutput() : void + { + $co = new CostObject(); + + $co->setCode('TestCode'); + self::assertEquals('TestCode', $co->getCode()); + } + + public function testDescriptionInputOutput() : void + { + $co = new CostObject(); + + $co->setDescription('TestDescription'); + self::assertEquals('TestDescription', $co->getDescription()); + } + + public function testParentInputOutput() : void + { + $co = new CostObject(); + + $co->setParent(1); + self::assertEquals(1, $co->getParent()); + } +}