From e448179f73808125f2da284507e7cc68cc199a61 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Tue, 2 Jan 2024 23:34:17 +0000 Subject: [PATCH] update --- Admin/Install/Admin.install.json | 10 + Admin/Install/Admin.php | 43 ++ Admin/Routes/Web/Api.php | 172 +++++++ Controller/ApiController.php | 58 ++- Controller/BackendController.php | 114 +++-- Models/ClientMapper.php | 2 + Models/PermissionCategory.php | 2 +- Models/SettingsEnum.php | 30 ++ Theme/Backend/attribute-type.tpl.php | 2 +- Theme/Backend/client-create.tpl.php | 24 +- Theme/Backend/client-profile-bills.tpl.php | 194 -------- Theme/Backend/client-profile-items.tpl.php | 2 +- Theme/Backend/client-profile.tpl.php | 523 ++++++++++++++------- info.json | 4 +- 14 files changed, 744 insertions(+), 436 deletions(-) create mode 100644 Admin/Install/Admin.install.json create mode 100644 Admin/Install/Admin.php create mode 100644 Admin/Routes/Web/Api.php create mode 100644 Models/SettingsEnum.php delete mode 100755 Theme/Backend/client-profile-bills.tpl.php diff --git a/Admin/Install/Admin.install.json b/Admin/Install/Admin.install.json new file mode 100644 index 0000000..cbe32b1 --- /dev/null +++ b/Admin/Install/Admin.install.json @@ -0,0 +1,10 @@ +[ + { + "description": "Default client segmentation (segment, section, sales group, product group)", + "type": "setting", + "name": "1003100001", + "content": "[\"segment\":1, \"section\":1, \"client_group\":1]", + "pattern": "", + "module": "ClientManagement" + } +] \ No newline at end of file diff --git a/Admin/Install/Admin.php b/Admin/Install/Admin.php new file mode 100644 index 0000000..3332c9a --- /dev/null +++ b/Admin/Install/Admin.php @@ -0,0 +1,43 @@ + __DIR__ . '/Admin.install.json']); + } +} diff --git a/Admin/Routes/Web/Api.php b/Admin/Routes/Web/Api.php new file mode 100644 index 0000000..f927940 --- /dev/null +++ b/Admin/Routes/Web/Api.php @@ -0,0 +1,172 @@ + [ + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiController:apiClientFind', + 'verb' => RouteVerb::GET, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + ], + '^.*/client/attribute$' => [ + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiAttributeController:apiClientAttributeCreate', + 'verb' => RouteVerb::PUT, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiAttributeController:apiClientAttributeUpdate', + 'verb' => RouteVerb::SET, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + ], + '^.*/client/attribute/type$' => [ + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiAttributeController:apiClientAttributeTypeCreate', + 'verb' => RouteVerb::PUT, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiAttributeController:apiClientAttributeTypeUpdate', + 'verb' => RouteVerb::SET, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + ], + '^.*/client/attribute/type/l11n$' => [ + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiAttributeController:apiClientAttributeTypeL11nCreate', + 'verb' => RouteVerb::PUT, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiAttributeController:apiClientAttributeTypeL11nUpdate', + 'verb' => RouteVerb::SET, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + ], + '^.*/client/attribute/value$' => [ + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiAttributeController:apiClientAttributeValueCreate', + 'verb' => RouteVerb::PUT, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiAttributeController:apiClientAttributeValueUpdate', + 'verb' => RouteVerb::SET, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + ], + '^.*/client/attribute/value$' => [ + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiAttributeController:apiClientAttributeValueL11nCreate', + 'verb' => RouteVerb::PUT, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiAttributeController:apiClientAttributeValueL11nUpdate', + 'verb' => RouteVerb::SET, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + ], + '^.*/client/l11n$' => [ + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiController:apiClientL11nCreate', + 'verb' => RouteVerb::PUT, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiController:apiClientL11nUpdate', + 'verb' => RouteVerb::SET, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + ], + '^.*/client/l11n/type$' => [ + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiController:apiClientL11nTypeCreate', + 'verb' => RouteVerb::PUT, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + [ + 'dest' => '\Modules\ClientManagement\Controller\ApiController:apiClientL11nTypeUpdate', + 'verb' => RouteVerb::SET, + 'permission' => [ + 'module' => ApiController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::CLIENT, + ], + ], + ], +]; diff --git a/Controller/ApiController.php b/Controller/ApiController.php index bffbbe5..85463dd 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -25,6 +25,7 @@ use Modules\ClientManagement\Models\ClientL11nMapper; use Modules\ClientManagement\Models\ClientL11nTypeMapper; use Modules\ClientManagement\Models\ClientMapper; use Modules\ClientManagement\Models\PermissionCategory; +use Modules\ClientManagement\Models\SettingsEnum; use Modules\Media\Models\MediaMapper; use Modules\Media\Models\PathSettings; use Modules\Organization\Models\UnitMapper; @@ -193,9 +194,40 @@ final class ApiController extends Controller ->apiClientAttributeCreate($internalRequest, $internalResponse); } + $this->createClientSegmentation($request, $response, $client); + $this->createStandardCreateResponse($request, $response, $client); } + private function createClientSegmentation(RequestAbstract $request, ResponseAbstract $response, Client $client) : void + { + /** @var \Model\Setting $settings */ + $settings = $this->app->appSettings->get(null, [ + SettingsEnum::DEFAULT_SEGMENTATION, + ]); + + $segmentation = \json_decode($settings->content, true); + if ($segmentation === false) { + return; + } + + $types = ClientAttributeTypeMapper::get() + ->where('name', \array_keys($segmentation), 'IN') + ->execute(); + + foreach ($types as $type) { + $internalResponse = clone $response; + $internalRequest = new HttpRequest(new HttpUri('')); + + $internalRequest->header->account = $request->header->account; + $internalRequest->setData('ref', $client->id); + $internalRequest->setData('type', $type->id); + $internalRequest->setData('value_id', $segmentation[$type->name]); + + $this->app->moduleManager->get('ClientManagement', 'ApiAttribute')->apiItemAttributeCreate($internalRequest, $internalResponse); + } + } + /** * Method to create news article from request. * @@ -219,25 +251,25 @@ final class ApiController extends Controller $client = new Client(); $client->number = $request->getDataString('number') ?? ''; $client->account = $account; + $client->unit = $request->getDataInt('unit') ?? 1; + // Handle main address $addr = new Address(); $addr->address = $request->getDataString('address') ?? ''; $addr->postal = $request->getDataString('postal') ?? ''; $addr->city = $request->getDataString('city') ?? ''; - $addr->setCountry($request->getDataString('country') ?? ISO3166TwoEnum::_XXX); $addr->state = $request->getDataString('state') ?? ''; + $addr->setCountry($request->getDataString('country') ?? ISO3166TwoEnum::_XXX); + $client->mainAddress = $addr; + // Try to find lat/lon through external API $geocoding = Nominatim::geocoding($addr->country, $addr->city, $addr->address); if ($geocoding === ['lat' => 0.0, 'lon' => 0.0]) { $geocoding = Nominatim::geocoding($addr->country, $addr->city); } - $addr->lat = $geocoding['lat']; - $addr->lon = $geocoding['lon']; - - $client->mainAddress = $addr; - - $client->unit = $request->getDataInt('unit'); + $client->mainAddress->lat = $geocoding['lat']; + $client->mainAddress->lon = $geocoding['lon']; return $client; } @@ -340,13 +372,13 @@ final class ApiController extends Controller */ private function updateMainAddressFromRequest(RequestAbstract $request, Address $address) : Address { - $address->name = $request->getDataString('name') ?? $address->name; - $address->fao = $request->getDataString('fao') ?? $address->fao; - $address->address = $request->getDataString('address') ?? $address->address; + $address->name = $request->getDataString('name') ?? $address->name; + $address->fao = $request->getDataString('fao') ?? $address->fao; + $address->address = $request->getDataString('address') ?? $address->address; $address->addressAddition = $request->getDataString('addition') ?? $address->addressAddition; - $address->postal = $request->getDataString('postal') ?? $address->postal; - $address->city = $request->getDataString('city') ?? $address->city; - $address->state = $request->getDataString('state') ?? $address->state; + $address->postal = $request->getDataString('postal') ?? $address->postal; + $address->city = $request->getDataString('city') ?? $address->city; + $address->state = $request->getDataString('state') ?? $address->state; $address->setCountry($request->getDataString('country') ?? $address->getCountry()); return $address; diff --git a/Controller/BackendController.php b/Controller/BackendController.php index 51f258d..d584c18 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -14,23 +14,29 @@ declare(strict_types=1); namespace Modules\ClientManagement\Controller; +use Modules\Admin\Models\LocalizationMapper; +use Modules\Admin\Models\SettingsEnum; +use Modules\Auditor\Models\AuditMapper; +use Modules\Billing\Models\Price\PriceMapper; +use Modules\Billing\Models\Price\PriceType; use Modules\Billing\Models\SalesBillMapper; +use Modules\ClientManagement\Models\Attribute\ClientAttributeMapper; use Modules\ClientManagement\Models\Attribute\ClientAttributeTypeL11nMapper; use Modules\ClientManagement\Models\Attribute\ClientAttributeTypeMapper; use Modules\ClientManagement\Models\Attribute\ClientAttributeValueMapper; use Modules\ClientManagement\Models\ClientMapper; use Modules\Media\Models\MediaMapper; use Modules\Media\Models\MediaTypeMapper; +use Modules\Organization\Models\Attribute\UnitAttributeMapper; use phpOMS\Asset\AssetType; use phpOMS\Contract\RenderableInterface; use phpOMS\DataStorage\Database\Query\Builder; use phpOMS\DataStorage\Database\Query\OrderType; -use phpOMS\Localization\ISO3166CharEnum; -use phpOMS\Localization\ISO3166NameEnum; use phpOMS\Localization\Money; use phpOMS\Message\RequestAbstract; use phpOMS\Message\ResponseAbstract; use phpOMS\Stdlib\Base\SmartDateTime; +use phpOMS\Utils\StringUtils; use phpOMS\Views\View; /** @@ -45,7 +51,7 @@ use phpOMS\Views\View; final class BackendController extends Controller { /** - * Routing end-point for application behaviour. + * Routing end-point for application behavior. * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response @@ -74,7 +80,7 @@ final class BackendController extends Controller } /** - * Routing end-point for application behaviour. + * Routing end-point for application behavior. * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response @@ -103,7 +109,7 @@ final class BackendController extends Controller } /** - * Routing end-point for application behaviour. + * Routing end-point for application behavior. * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response @@ -138,7 +144,7 @@ final class BackendController extends Controller } /** - * Routing end-point for application behaviour. + * Routing end-point for application behavior. * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response @@ -168,7 +174,7 @@ final class BackendController extends Controller } /** - * Routing end-point for application behaviour. + * Routing end-point for application behavior. * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response @@ -189,7 +195,7 @@ final class BackendController extends Controller } /** - * Routing end-point for application behaviour. + * Routing end-point for application behavior. * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response @@ -221,11 +227,32 @@ final class BackendController extends Controller ->with('mainAddress') ->with('files')->limit(5, 'files')->sort('files/id', OrderType::DESC) ->with('notes')->limit(5, 'notes')->sort('notes/id', OrderType::DESC) + ->with('attributes') + ->with('attributes/type') + ->with('attributes/type/l11n') + ->with('attributes/value') ->where('id', (int) $request->getData('id')) ->execute(); $view->data['client'] = $client; + /** @var \Model\Setting $settings */ + $settings = $this->app->appSettings->get(null, [ + SettingsEnum::DEFAULT_LOCALIZATION, + ]); + + + $view->data['attributeView'] = new \Modules\Attribute\Theme\Backend\Components\AttributeView($this->app->l11nManager, $request, $response); + $view->data['attributeView']->data['defaultlocalization'] = LocalizationMapper::get()->where('id', (int) $settings->id)->execute(); + + /** @var \Modules\Attribute\Models\AttributeType[] $attributeTypes */ + $attributeTypes = ClientAttributeTypeMapper::getAll() + ->with('l11n') + ->where('l11n/language', $response->header->l11n->language) + ->execute(); + + $view->data['attributeTypes'] = $attributeTypes; + // Get item profile image // It might not be part of the 5 newest item files from above // @todo It would be nice to have something like this as a default method in the model e.g. @@ -253,44 +280,53 @@ final class BackendController extends Controller $view->data['clientImage'] = $clientImage; - // stats - if ($this->app->moduleManager->isActive('Billing')) { - $ytd = SalesBillMapper::getSalesByClientId($client->id, new SmartDateTime('Y-01-01'), new SmartDateTime('now')); - $mtd = SalesBillMapper::getSalesByClientId($client->id, new SmartDateTime('Y-m-01'), new SmartDateTime('now')); - $lastOrder = SalesBillMapper::getLastOrderDateByClientId($client->id); - $newestInvoices = SalesBillMapper::getAll() - ->with('type') - ->with('type/l11n') - ->with('client') - ->where('client', $client->id) - ->where('type/l11n/language', $response->header->l11n->language) - ->sort('id', OrderType::DESC) - ->limit(5) - ->execute(); + $businessStart = UnitAttributeMapper::get() + ->with('type') + ->with('value') + ->where('ref', $this->app->unitId) + ->where('type/name', 'business_year_start') + ->execute(); - $monthlySalesCosts = SalesBillMapper::getClientMonthlySalesCosts($client->id, (new SmartDateTime('now'))->createModify(-1), new SmartDateTime('now')); - $items = SalesBillMapper::getClientItem($client->id, (new SmartDateTime('now'))->createModify(-1), new SmartDateTime('now')); - } else { - $ytd = new Money(); - $mtd = new Money(); - $lastOrder = null; - $newestInvoices = []; - $monthlySalesCosts = []; - $items = []; - } + $view->data['business_start'] = $businessStart->id === 0 ? 1 : $businessStart->value->getValue(); - $view->data['ytd'] = $ytd; - $view->data['mtd'] = $mtd; - $view->data['lastOrder'] = $lastOrder; - $view->data['newestInvoices'] = $newestInvoices; - $view->data['monthlySalesCosts'] = $monthlySalesCosts; - $view->data['items'] = $items; + /** @var \Modules\Billing\Models\Price\Price[] $prices */ + $prices = PriceMapper::getAll() + ->where('client', $client->id) + ->where('type', PriceType::SALES) + ->execute(); + + $view->data['prices'] = $prices; + + /** @var \Modules\Auditor\Models\Audit[] $audits */ + $audits = AuditMapper::getAll() + ->where('type', StringUtils::intHash(ClientMapper::class)) + ->where('module', 'ClientManagement') + ->where('ref', (string) $client->id) + ->execute(); + + // @todo join audit with files, attributes, localization, prices, notes, ... + + $view->data['audits'] = $audits; + + /** @var \Modules\Media\Models\Media[] $files */ + $files = MediaMapper::getAll() + ->with('types') + ->join('id', ClientMapper::class, 'files') // id = media id, files = client relations + ->on('id', $client->id, relation: 'files') // id = item id + ->execute(); + + $view->data['files'] = $files; + + $view->data['media-upload'] = new \Modules\Media\Theme\Backend\Components\Upload\BaseView($this->app->l11nManager, $request, $response); + $view->data['note'] = new \Modules\Editor\Theme\Backend\Components\Note\BaseView($this->app->l11nManager, $request, $response); + + $view->data['hasBilling'] = $this->app->moduleManager->isActive('Billing'); return $view; } /** - * Routing end-point for application behaviour. + * Routing end-point for application behavior. * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response diff --git a/Models/ClientMapper.php b/Models/ClientMapper.php index 3e61117..eb3629e 100755 --- a/Models/ClientMapper.php +++ b/Models/ClientMapper.php @@ -22,6 +22,8 @@ use Modules\Media\Models\MediaMapper; use Modules\Payment\Models\PaymentMapper; use Modules\Profile\Models\ContactElementMapper; use phpOMS\DataStorage\Database\Mapper\DataMapperFactory; +use phpOMS\DataStorage\Database\Query\Builder; +use phpOMS\Stdlib\Base\FloatInt; /** * Client mapper class. diff --git a/Models/PermissionCategory.php b/Models/PermissionCategory.php index b3a0d4e..f8b754e 100755 --- a/Models/PermissionCategory.php +++ b/Models/PermissionCategory.php @@ -17,7 +17,7 @@ namespace Modules\ClientManagement\Models; use phpOMS\Stdlib\Base\Enum; /** - * Permision state enum. + * Permission category enum. * * @package Modules\ClientManagement\Models * @license OMS License 2.0 diff --git a/Models/SettingsEnum.php b/Models/SettingsEnum.php new file mode 100644 index 0000000..e29ab90 --- /dev/null +++ b/Models/SettingsEnum.php @@ -0,0 +1,30 @@ +data['nav']->render(); ?>
getHtml('Language', '0', '0'); ?>download
- +
diff --git a/Theme/Backend/client-create.tpl.php b/Theme/Backend/client-create.tpl.php index 611231b..53346d6 100755 --- a/Theme/Backend/client-create.tpl.php +++ b/Theme/Backend/client-create.tpl.php @@ -20,14 +20,14 @@ echo $this->data['nav']->render(); ?>
@@ -44,11 +44,11 @@ echo $this->data['nav']->render(); ?>
-
+
-
+
-
+
@@ -264,7 +264,7 @@ echo $this->data['nav']->render(); ?> $footerView->setPage(1); ?>
- +
diff --git a/Theme/Backend/client-profile-bills.tpl.php b/Theme/Backend/client-profile-bills.tpl.php deleted file mode 100755 index c22cdb4..0000000 --- a/Theme/Backend/client-profile-bills.tpl.php +++ /dev/null @@ -1,194 +0,0 @@ -data['newestInvoices'] ?? []; - -?> - -
-
-
-
getHtml('Bills'); ?>download
-
getHtml('Logs'); ?>download
- - - - $value) : - ++$count; - $url = UriFactory::build('{/base}/sales/bill?{?}&id=' . $value->id); - ?> - -
- getHtml('ID', '0', '0'); ?> - - - - getHtml('Type'); ?> - - - - getHtml('ClientID'); ?> - - - - getHtml('Client'); ?> - - - - getHtml('Address'); ?> - - - - getHtml('Postal'); ?> - - - - getHtml('City'); ?> - - - - getHtml('Country'); ?> - - - - getHtml('Net'); ?> - - - - getHtml('Profit'); ?> - - - - getHtml('Created'); ?> - - - -
- getNumber(); ?> - type->getL11n(); ?> - client->number; ?> - printHtml($value->billTo); ?> - billAddress; ?> - billZip; ?> - billCity; ?> - billCountry; ?> - getCurrency($value->netSales); ?> - getCurrency($value->netProfit); ?> - createdAt->format('Y-m-d'); ?> - - -
getHtml('Empty', '0', '0'); ?> - -
-
-
-
diff --git a/Theme/Backend/client-profile-items.tpl.php b/Theme/Backend/client-profile-items.tpl.php index 0cb6a9c..27e9fd8 100755 --- a/Theme/Backend/client-profile-items.tpl.php +++ b/Theme/Backend/client-profile-items.tpl.php @@ -23,7 +23,7 @@ $items = $this->data['items'] ?? [];
getHtml('Items'); ?>download
- +