From af797be07cd4adee259a2ec84b0f21123bcf8684 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sun, 4 Apr 2021 17:10:52 +0200 Subject: [PATCH] many fixes and expands and module expansions --- Admin/Install/Navigation.install.json | 77 +++++++++++++ Admin/Install/db.json | 12 ++ Admin/Routes/Web/Backend.php | 55 +++++++++ Controller/BackendController.php | 124 ++++++++++++++++++++- Models/ItemAttributeType.php | 10 +- Models/ItemAttributeTypeL11n.php | 12 +- Models/ItemAttributeTypeMapper.php | 2 + Models/PermissionState.php | 2 + Theme/Backend/Lang/Navigation.en.lang.php | 4 + Theme/Backend/attribute-type-list.tpl.php | 70 ++++++++++++ Theme/Backend/attribute-type.tpl.php | 0 Theme/Backend/attribute-value-list.tpl.php | 0 Theme/Backend/attribute-value.tpl.php | 0 Theme/Backend/sales-item-profile.tpl.php | 103 +++++++++++------ 14 files changed, 425 insertions(+), 46 deletions(-) create mode 100644 Theme/Backend/attribute-type-list.tpl.php create mode 100644 Theme/Backend/attribute-type.tpl.php create mode 100644 Theme/Backend/attribute-value-list.tpl.php create mode 100644 Theme/Backend/attribute-value.tpl.php diff --git a/Admin/Install/Navigation.install.json b/Admin/Install/Navigation.install.json index 7193faf..c4bc50d 100755 --- a/Admin/Install/Navigation.install.json +++ b/Admin/Install/Navigation.install.json @@ -1,4 +1,66 @@ [ + { + "id": 1004801001, + "pid": "/", + "type": 2, + "subtype": 0, + "name": "ItemManagement", + "uri": null, + "target": "self", + "icon": "fa fa-usd", + "order": 20, + "from": "ItemManagement", + "permission": { "permission": 2, "type": null, "element": null }, + "parent": 0, + "children": [ + { + "id": 1004802001, + "pid": "/", + "type": 2, + "subtype": 1, + "name": "Attributes", + "uri": "{/prefix}item/attribute/type?{?}", + "target": "self", + "icon": null, + "order": 15, + "from": "Sales", + "permission": { "permission": 2, "type": null, "element": null }, + "parent": 1004801001, + "children": [ + { + "id": 1004802002, + "pid": "/item", + "type": 3, + "subtype": 1, + "name": "Types", + "uri": "{/prefix}item/attribute/type?{?}", + "target": "self", + "icon": null, + "order": 15, + "from": "Sales", + "permission": { "permission": 2, "type": null, "element": null }, + "parent": 1004802001, + "children": [] + }, + { + "id": 1004802003, + "pid": "/item", + "type": 3, + "subtype": 1, + "name": "Values", + "uri": "{/prefix}item/attribute/value?{?}", + "target": "self", + "icon": null, + "order": 15, + "from": "Sales", + "permission": { "permission": 2, "type": null, "element": null }, + "parent": 1004802001, + "children": [] + } + ] + } + ] + }, { "id": 1004805001, "pid": "/", @@ -246,5 +308,20 @@ "children": [] } ] + }, + { + "id": 1004809001, + "pid": "/sales/analysis", + "type": 3, + "subtype": 1, + "name": "Article", + "uri": "{/prefix}sales/analysis/item", + "target": "self", + "icon": null, + "order": 4, + "from": "ItemManagement", + "permission": { "permission": 2, "type": null, "element": null }, + "parent": 1001602001, + "children": [] } ] diff --git a/Admin/Install/db.json b/Admin/Install/db.json index ff0497b..994ff68 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -114,6 +114,18 @@ "name": "itemmgmt_attr_type_custom", "type": "TINYINT(1)", "null": false + }, + "itemmgmt_attr_type_required": { + "description": "Every item must have this attribute type if set to true.", + "name": "itemmgmt_attr_type_required", + "type": "TINYINT(1)", + "null": false + }, + "itemmgmt_attr_type_pattern": { + "description": "This is a regex validation pattern.", + "name": "itemmgmt_attr_type_pattern", + "type": "VARCHAR(255)", + "null": false } } }, diff --git a/Admin/Routes/Web/Backend.php b/Admin/Routes/Web/Backend.php index d0068c8..4a53334 100755 --- a/Admin/Routes/Web/Backend.php +++ b/Admin/Routes/Web/Backend.php @@ -6,6 +6,50 @@ use phpOMS\Account\PermissionType; use phpOMS\Router\RouteVerb; return [ + '^.*/item/attribute/type.*$' => [ + [ + 'dest' => '\Modules\ItemManagement\Controller\BackendController:viewItemManagementAttributeTypes', + 'verb' => RouteVerb::GET, + 'permission' => [ + 'module' => BackendController::MODULE_NAME, + 'type' => PermissionType::READ, + 'state' => PermissionState::ATTRIBUTE, + ], + ], + ], + '^.*/item/attribute/value.*$' => [ + [ + 'dest' => '\Modules\ItemManagement\Controller\BackendController:viewItemManagementAttributeValues', + 'verb' => RouteVerb::GET, + 'permission' => [ + 'module' => BackendController::MODULE_NAME, + 'type' => PermissionType::READ, + 'state' => PermissionState::ATTRIBUTE, + ], + ], + ], + '^.*/item/attribute/type.*$' => [ + [ + 'dest' => '\Modules\ItemManagement\Controller\BackendController:viewItemManagementAttributeTypes', + 'verb' => RouteVerb::GET, + 'permission' => [ + 'module' => BackendController::MODULE_NAME, + 'type' => PermissionType::READ, + 'state' => PermissionState::ATTRIBUTE, + ], + ], + ], + '^.*/item/attribute/value.*$' => [ + [ + 'dest' => '\Modules\ItemManagement\Controller\BackendController:viewItemManagementAttributeValues', + 'verb' => RouteVerb::GET, + 'permission' => [ + 'module' => BackendController::MODULE_NAME, + 'type' => PermissionType::READ, + 'state' => PermissionState::ATTRIBUTE, + ], + ], + ], '^.*/sales/item/list.*$' => [ [ 'dest' => '\Modules\ItemManagement\Controller\BackendController:viewItemManagementSalesList', @@ -105,4 +149,15 @@ return [ ], ], ], + '^.*/sales/analysis/item(\?.*|$)$' => [ + [ + 'dest' => '\Modules\ItemManagement\Controller\BackendController:viewItemAnalysis', + 'verb' => RouteVerb::GET, + 'permission' => [ + 'module' => BackendController::MODULE_NAME, + 'type' => PermissionType::READ, + 'state' => PermissionState::SALES_ITEM, + ], + ], + ], ]; diff --git a/Controller/BackendController.php b/Controller/BackendController.php index 25b6f8b..e039222 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -15,11 +15,14 @@ declare(strict_types=1); namespace Modules\ItemManagement\Controller; use Model\SettingsEnum; +use Modules\Media\Models\Media; use Modules\Admin\Models\LocalizationMapper; use Modules\Billing\Models\BillTypeL11n; use Modules\Billing\Models\SalesBillMapper; use Modules\ItemManagement\Models\ItemAttributeMapper; +use Modules\ItemManagement\Models\ItemAttributeTypeMapper; use Modules\ItemManagement\Models\ItemL11nMapper; +use Modules\ItemManagement\Models\ItemL11nType; use Modules\ItemManagement\Models\ItemMapper; use phpOMS\Asset\AssetType; use phpOMS\Contract\RenderableInterface; @@ -28,6 +31,7 @@ use phpOMS\Message\RequestAbstract; use phpOMS\Message\ResponseAbstract; use phpOMS\Stdlib\Base\SmartDateTime; use phpOMS\Views\View; +use Modules\ItemManagement\Models\ItemAttributeValueMapper; /** * ItemManagement controller class. @@ -39,6 +43,111 @@ use phpOMS\Views\View; */ 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 + * + * @since 1.0.0 + * @codeCoverageIgnore + */ + public function viewItemManagementAttributeTypes(RequestAbstract $request, ResponseAbstract $response, $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + $view->setTemplate('/Modules/ItemManagement/Theme/Backend/attribute-type-list'); + $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1004801001, $request, $response)); + + $attributes = ItemAttributeTypeMapper::with('language', $response->getLanguage()) + ::getAll(); + + $view->addData('attributes', $attributes); + + 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 viewItemManagementAttributeValues(RequestAbstract $request, ResponseAbstract $response, $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + $view->setTemplate('/Modules/ItemManagement/Theme/Backend/attribute-value-list'); + $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1004801001, $request, $response)); + + $attributes = ItemAttributeValueMapper::with('language', $response->getLanguage()) + ::getAll(); + + $view->addData('attributes', $attributes); + + 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 viewItemManagementAttributeType(RequestAbstract $request, ResponseAbstract $response, $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + $view->setTemplate('/Modules/ItemManagement/Theme/Backend/attribute-type'); + $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1004801001, $request, $response)); + + $attribute = ItemAttributeTypeMapper::with('language', $response->getLanguage()) + ::get((int) $request->getData('id')); + + $view->addData('attribute', $attribute); + + 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 viewItemManagementAttributeValue(RequestAbstract $request, ResponseAbstract $response, $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + $view->setTemplate('/Modules/ItemManagement/Theme/Backend/attribute-value'); + $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1004801001, $request, $response)); + + $attribute = ItemAttributeValueMapper::with('language', $response->getLanguage()) + ::get((int) $request->getData('id')); + + $view->addData('attribute', $attribute); + + return $view; + } + /** * Routing end-point for application behaviour. * @@ -57,7 +166,13 @@ final class BackendController extends Controller $view->setTemplate('/Modules/ItemManagement/Theme/Backend/sales-item-list'); $view->addData('nav', $this->app->moduleManager->get('Navigation')->createNavigationMid(1004805001, $request, $response)); - $items = ItemMapper::with('language', $response->getLanguage())::getAfterPivot(0, null, 25); + $items = ItemMapper::with('language', $response->getLanguage()) + ::with('type', 'backend_image', models: [Media::class]) // @todo: it would be nicer if I coult say files:type or files/type and remove the models parameter? + ::with('notes', models: null) + ::with('attributes', models: null) + ::with('title', ['name1', 'name2', 'name3'], comparison: 'in', models: [ItemL11nType::class]) // @todo: profile, why does this have almost no impact on the sql performance? + ::getAfterPivot(0, null, 25); + $view->addData('items', $items); return $view; @@ -181,12 +296,12 @@ final class BackendController extends Controller * @param ResponseAbstract $response Response * @param mixed $data Generic data * - * @return RenderableInterface + * @return View * * @since 1.0.0 * @codeCoverageIgnore */ - public function viewItemManagementSalesItem(RequestAbstract $request, ResponseAbstract $response, $data = null) : RenderableInterface + public function viewItemManagementSalesItem(RequestAbstract $request, ResponseAbstract $response, $data = null) : View { $head = $response->get('Content')->getData('head'); $head->addAsset(AssetType::CSS, 'Resources/chartjs/Chartjs/chart.css'); @@ -226,6 +341,7 @@ final class BackendController extends Controller // @todo: why is the conditional array necessary, shouldn't the mapper realize when it mustn't use the conditional (when the field doesn't exist in the mapper) $newestInvoices = SalesBillMapper::with('language', $response->getLanguage(), [BillTypeL11n::class])::getNewestItemInvoices($item->getId(), 5); $topCustomers = SalesBillMapper::getItemTopCustomers($item->getId(), new SmartDateTime('Y-01-01'), new SmartDateTime('now'), 5); + $allInvoices = SalesBillMapper::getItemBills($item->getId(), new SmartDateTime('Y-01-01'), new SmartDateTime('now')); $regionSales = SalesBillMapper::getItemRegionSales($item->getId(), new SmartDateTime('Y-01-01'), new SmartDateTime('now')); $countrySales = SalesBillMapper::getItemCountrySales($item->getId(), new SmartDateTime('Y-01-01'), new SmartDateTime('now'), 5); $monthlySalesCosts = SalesBillMapper::getItemMonthlySalesCosts($item->getId(), (new SmartDateTime('now'))->createModify(-1), new SmartDateTime('now')); @@ -235,6 +351,7 @@ final class BackendController extends Controller $avg = new Money(); $lastOrder = null; $newestInvoices = []; + $allInvoices = []; $topCustomers = []; $regionSales = []; $countrySales = []; @@ -246,6 +363,7 @@ final class BackendController extends Controller $view->addData('avg', $avg); $view->addData('lastOrder', $lastOrder); $view->addData('newestInvoices', $newestInvoices); + $view->addData('allInvoices', $allInvoices); $view->addData('topCustomers', $topCustomers); $view->addData('regionSales', $regionSales); $view->addData('countrySales', $countrySales); diff --git a/Models/ItemAttributeType.php b/Models/ItemAttributeType.php index 9f7a9fd..fe1e935 100755 --- a/Models/ItemAttributeType.php +++ b/Models/ItemAttributeType.php @@ -41,7 +41,7 @@ class ItemAttributeType implements \JsonSerializable, ArrayableInterface * @var string * @since 1.0.0 */ - protected string $name = ''; // @todo: currently not filled, should be used as identifier or if not required removed (at the moment it seems like it is useless?!) + public string $name = ''; // @todo: currently not filled, should be used as identifier or if not required removed (at the moment it seems like it is useless?!) /** * Which field data type is required (string, int, ...) in the value @@ -59,12 +59,16 @@ class ItemAttributeType implements \JsonSerializable, ArrayableInterface */ protected bool $custom = false; + public string $validationPattern = ''; + + public bool $isRequired = false; + /** * Localization * - * @var int|int[]|ItemAttributeTypeL11n|ItemAttributeTypeL11n[] + * @var ItemAttributeTypeL11n */ - protected $l11n = 0; + protected string | ItemAttributeTypeL11n $l11n; /** * Possible default attribute values diff --git a/Models/ItemAttributeTypeL11n.php b/Models/ItemAttributeTypeL11n.php index 558392d..9cc06d4 100755 --- a/Models/ItemAttributeTypeL11n.php +++ b/Models/ItemAttributeTypeL11n.php @@ -38,12 +38,12 @@ class ItemAttributeTypeL11n implements \JsonSerializable, ArrayableInterface /** * Item ID. * - * @var int|ItemL11nType + * @var int|ItemAttributeType * @since 1.0.0 */ protected int | -ItemL11nType $type = 0; +ItemAttributeType $type = 0; /** * Language. @@ -64,13 +64,13 @@ ItemL11nType $type = 0; /** * Constructor. * - * @param int|ItemL11nType $type Attribute type + * @param int|ItemAttributeType $type Attribute type * @param string $title Localized title * @param string $language Language * * @since 1.0.0 */ - public function __construct(int | ItemL11nType $type = 0, string $title = '', string $language = ISO639x1Enum::_EN) + public function __construct(int | ItemAttributeType $type = 0, string $title = '', string $language = ISO639x1Enum::_EN) { $this->type = $type; $this->title = $title; @@ -92,11 +92,11 @@ ItemL11nType $type = 0; /** * Get attribute type * - * @return int|ItemL11nType + * @return int|ItemAttributeType * * @since 1.0.0 */ - public function getType() + public function getType() : int | ItemAttributeType { return $this->type; } diff --git a/Models/ItemAttributeTypeMapper.php b/Models/ItemAttributeTypeMapper.php index 6be4170..813de7c 100755 --- a/Models/ItemAttributeTypeMapper.php +++ b/Models/ItemAttributeTypeMapper.php @@ -37,6 +37,8 @@ final class ItemAttributeTypeMapper extends DataMapperAbstract 'itemmgmt_attr_type_name' => ['name' => 'itemmgmt_attr_type_name', 'type' => 'string', 'internal' => 'name', 'autocomplete' => true], 'itemmgmt_attr_type_fields' => ['name' => 'itemmgmt_attr_type_fields', 'type' => 'int', 'internal' => 'fields'], 'itemmgmt_attr_type_custom' => ['name' => 'itemmgmt_attr_type_custom', 'type' => 'bool', 'internal' => 'custom'], + 'itemmgmt_attr_type_pattern' => ['name' => 'itemmgmt_attr_type_pattern', 'type' => 'bool', 'internal' => 'validationPattern'], + 'itemmgmt_attr_type_required' => ['name' => 'itemmgmt_attr_type_required', 'type' => 'bool', 'internal' => 'isRequired'], ]; /** diff --git a/Models/PermissionState.php b/Models/PermissionState.php index 141a1cf..555e873 100755 --- a/Models/PermissionState.php +++ b/Models/PermissionState.php @@ -31,4 +31,6 @@ abstract class PermissionState extends Enum public const PURCHASE_ITEM = 2; public const STOCK_ITEM = 3; + + public const ATTRIBUTE = 4; } diff --git a/Theme/Backend/Lang/Navigation.en.lang.php b/Theme/Backend/Lang/Navigation.en.lang.php index beb3bd9..a20bad2 100755 --- a/Theme/Backend/Lang/Navigation.en.lang.php +++ b/Theme/Backend/Lang/Navigation.en.lang.php @@ -14,6 +14,10 @@ declare(strict_types=1); return ['Navigation' => [ 'Analyze' => 'Analyze', + 'Attributes' => 'Attributes', + 'Types' => 'Types', + 'Values' => 'Values', 'Create' => 'Create', 'List' => 'List', + 'ItemManagement' => 'Item Management', ]]; diff --git a/Theme/Backend/attribute-type-list.tpl.php b/Theme/Backend/attribute-type-list.tpl.php new file mode 100644 index 0000000..d89d5db --- /dev/null +++ b/Theme/Backend/attribute-type-list.tpl.php @@ -0,0 +1,70 @@ +getData('attributes'); + +echo $this->getData('nav')->render(); ?> + +
+
+
+
getHtml('AttributeTypes'); ?>
+ + + + + $value) : ++$count; + $url = UriFactory::build('{/prefix}item/attribute/type?{?}&id=' . $value->getId()); + ?> + +
getHtml('ID', '0', '0'); ?> + + + + getHtml('Name'); ?> + + + +
getId(); ?> + printHtml($value->getL11n()); ?> + + +
getHtml('Empty', '0', '0'); ?> + +
+
+
+
diff --git a/Theme/Backend/attribute-type.tpl.php b/Theme/Backend/attribute-type.tpl.php new file mode 100644 index 0000000..e69de29 diff --git a/Theme/Backend/attribute-value-list.tpl.php b/Theme/Backend/attribute-value-list.tpl.php new file mode 100644 index 0000000..e69de29 diff --git a/Theme/Backend/attribute-value.tpl.php b/Theme/Backend/attribute-value.tpl.php new file mode 100644 index 0000000..e69de29 diff --git a/Theme/Backend/sales-item-profile.tpl.php b/Theme/Backend/sales-item-profile.tpl.php index 960195a..fc63cea 100755 --- a/Theme/Backend/sales-item-profile.tpl.php +++ b/Theme/Backend/sales-item-profile.tpl.php @@ -29,6 +29,7 @@ $notes = $item->getNotes(); $files = $item->getFiles(); $newestInvoices = $this->getData('newestInvoices') ?? []; +$allInvoices = $this->getData('allInvoices') ?? []; $topCustomers = $this->getData('topCustomers') ?? []; $regionSales = $this->getData('regionSales') ?? []; $countrySales = $this->getData('countrySales') ?? []; @@ -56,7 +57,8 @@ echo $this->getData('nav')->render();
  • -
  • +
  • +
  • @@ -168,8 +170,8 @@ echo $this->getData('nav')->render(); $url = UriFactory::build('{/prefix}editor/single?{?}&id=' . $note->getId()); ?> - title; ?> - createdAt->format('Y-m-d'); ?> + printHtml($note->title); ?> + printHtml($note->createdAt->format('Y-m-d')); ?> @@ -189,9 +191,9 @@ echo $this->getData('nav')->render(); $url = UriFactory::build('{/prefix}media/single?{?}&id=' . $file->getId()); ?> - name; ?> - extension; ?> - createdAt->format('Y-m-d'); ?> + printHtml($file->name); ?> + printHtml($file->extension); ?> + printHtml($file->createdAt->format('Y-m-d')); ?> @@ -215,11 +217,11 @@ echo $this->getData('nav')->render(); $url = UriFactory::build('{/prefix}sales/bill?{?}&id=' . $invoice->getId()); ?> - getNumber(); ?> - type->getL11n(); ?> - billTo; ?> - net->getCurrency(); ?> - createdAt->format('Y-m-d'); ?> + printHtml($invoice->getNumber()); ?> + printHtml($invoice->type->getL11n()); ?> + printHtml($invoice->billTo); ?> + printHtml($invoice->net->getCurrency()); ?> + printHtml($invoice->createdAt->format('Y-m-d')); ?> @@ -513,7 +515,7 @@ echo $this->getData('nav')->render(); - + @@ -557,7 +559,7 @@ echo $this->getData('nav')->render();
    -

    getHtml('Customer'); ?>

    +

    getHtml('Pricing'); ?>

    @@ -605,28 +607,30 @@ echo $this->getData('nav')->render();
    - - - - - - $value) : ++$c; - $url = UriFactory::build('{/prefix}admin/group/settings?{?}&id=' . $value->getId()); ?> - - + $value) : ++$c; + $url = UriFactory::build('{/prefix}admin/group/settings?{?}&id=' . $value->getId()); ?> + + +
    getHtml('Prices'); ?>
    - getHtml('ID', '0', '0'); ?> - getHtml('Name'); ?> -
    - getId(); ?> - printHtml($value->name); ?> - - +
    +
    getHtml('Prices'); ?>
    + + -
    getHtml('Empty', '0', '0'); ?> - -
    +
    + getHtml('ID', '0', '0'); ?> + getHtml('Name'); ?> +
    + getId(); ?> + printHtml($value->name); ?> + + +
    getHtml('Empty', '0', '0'); ?> + +
    +
    @@ -900,6 +904,37 @@ echo $this->getData('nav')->render(); +
    +
    +
    +
    +
    getHtml('RecentInvoices'); ?>
    + + + + + getId()); + ?> + +
    getHtml('Number'); ?> + getHtml('Type'); ?> + getHtml('Name'); ?> + getHtml('Net'); ?> + getHtml('Date'); ?> +
    getNumber(); ?> + type->getL11n(); ?> + billTo; ?> + net->getCurrency(); ?> + createdAt->format('Y-m-d'); ?> + +
    +
    +
    +
    +
    + +