diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml index adb8716..75cb759 100755 --- a/.github/workflows/greetings.yml +++ b/.github/workflows/greetings.yml @@ -9,5 +9,5 @@ jobs: - 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.' + issue-message: 'Thank you for creating 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/Admin/Install/Media.install.json b/Admin/Install/Media.install.json index 7de8713..264f9b4 100755 --- a/Admin/Install/Media.install.json +++ b/Admin/Install/Media.install.json @@ -12,61 +12,5 @@ "name": "Items", "virtualPath": "/Modules/ItemManagement", "user": 1 - }, - { - "type": "type", - "name": "item_profile_image", - "l11n": [ - { - "title": "Profile image", - "lang": "en" - }, - { - "title": "Profilbild", - "lang": "de" - } - ] - }, - { - "type": "type", - "name": "item_demo_download", - "l11n": [ - { - "title": "Public Download", - "lang": "en" - }, - { - "title": "Oeffentlich Download", - "lang": "de" - } - ] - }, - { - "type": "type", - "name": "item_private_download", - "l11n": [ - { - "title": "Private Download", - "lang": "en" - }, - { - "title": "Privat Download", - "lang": "de" - } - ] - }, - { - "type": "type", - "name": "item_purchase_download", - "l11n": [ - { - "title": "Purchased Download", - "lang": "en" - }, - { - "title": "Gekaufter Download", - "lang": "de" - } - ] } ] \ No newline at end of file diff --git a/Admin/Install/Tag.install.json b/Admin/Install/Tag.install.json new file mode 100644 index 0000000..aa08eee --- /dev/null +++ b/Admin/Install/Tag.install.json @@ -0,0 +1,23 @@ +[ + { + "name": "item_demo_download", + "l11n": { + "en": "Item Download", + "de": "Artikel Download" + } + }, + { + "name": "item_private_download", + "l11n": { + "en": "Private Item Download", + "de": "Privater Artikel Download" + } + }, + { + "name": "item_purchase_download", + "l11n": { + "en": "Purchased Download", + "de": "Gekaufter Download" + } + } +] \ No newline at end of file diff --git a/Admin/Install/Tag.php b/Admin/Install/Tag.php new file mode 100644 index 0000000..da9ed07 --- /dev/null +++ b/Admin/Install/Tag.php @@ -0,0 +1,43 @@ + __DIR__ . '/Tag.install.json']); + } +} diff --git a/Admin/Install/attributes.json b/Admin/Install/attributes.json index df491ef..1c6f608 100755 --- a/Admin/Install/attributes.json +++ b/Admin/Install/attributes.json @@ -483,8 +483,8 @@ { "value": 1, "l11n": { - "en": "Type 1", - "de": "Typ 1" + "en": "Product Type 1", + "de": "Produkttyp 1" } } ] diff --git a/Controller/ApiAttributeController.php b/Controller/ApiAttributeController.php index 81f7ff1..d34bbb0 100644 --- a/Controller/ApiAttributeController.php +++ b/Controller/ApiAttributeController.php @@ -66,7 +66,7 @@ final class ApiAttributeController extends Controller ->where('id', (int) $request->getData('type')) ->execute(); - if (!$type->repeatable) { + if (!$type->isRepeatable) { $attr = ItemAttributeMapper::count() ->with('type') ->where('type/id', $type->id) diff --git a/Controller/ApiController.php b/Controller/ApiController.php index 9516a61..ed3d8f3 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -32,8 +32,8 @@ use Modules\ItemManagement\Models\SettingsEnum as ItemSettingsEnum; use Modules\ItemManagement\Models\StockIdentifierType; use Modules\Media\Models\Collection; use Modules\Media\Models\CollectionMapper; -use Modules\Media\Models\MediaTypeMapper; use Modules\Media\Models\PathSettings; +use Modules\Tag\Models\TagMapper; use phpOMS\Account\PermissionType; use phpOMS\Localization\BaseStringL11n; use phpOMS\Localization\BaseStringL11nType; @@ -256,15 +256,57 @@ final class ApiController extends Controller $this->createModel($request->header->account, $item, ItemMapper::class, 'item', $request->getOrigin()); $this->app->dbPool->get()->con->commit(); + // Define names + $names = []; + if ($request->hasData('name1')) { + $names = ItemL11nTypeMapper::getAll() + ->where('title', ['name1', 'name2']) + ->executeGetArray(); + + foreach ($names as $type) { + $names[$type->title] = $type; + } + + $internalResponse = new HttpResponse(); + $internalRequest = new HttpRequest(); + + $internalRequest->header->account = $request->header->account; + + $internalRequest->setData('item', $item->id); + $internalRequest->setData('type', $names['name1']->id); + $internalRequest->setData('content', $request->getDataString('name1')); + $internalRequest->setData('language', $request->getDataString('language') ?? $request->header->l11n->language); + + $this->apiItemL11nCreate($internalRequest, $internalResponse); + + if ($request->hasData('name2')) { + $internalResponse = new HttpResponse(); + $internalRequest = new HttpRequest(); + + $internalRequest->header->account = $request->header->account; + + $internalRequest->setData('item', $item->id); + $internalRequest->setData('type', $names['name2']->id); + $internalRequest->setData('content', $request->getDataString('name2')); + $internalRequest->setData('language', $request->getDataString('language') ?? $request->header->l11n->language); + + $this->apiItemL11nCreate($internalRequest, $internalResponse); + } + } + // Define default item containers /** @var \Modules\Attribute\Models\AttributeType[] $types */ $types = ItemAttributeTypeMapper::getAll() - ->where('name', ['default_sales_container', 'default_purchase_container'], 'IN') + ->where('name', ['default_sales_container', 'default_purchase_container', 'hs_code'], 'IN') ->executeGetArray(); $primaryContainer = \reset($item->container); if ($primaryContainer !== false) { foreach ($types as $type) { + if (\stripos($type->name, '_container') === false) { + continue; + } + $internalResponse = clone $response; $internalRequest = new HttpRequest(); @@ -277,6 +319,63 @@ final class ApiController extends Controller } } + // Guess hs_code + /* Alternatively find via segmentation + if ($item->stockIdentifier !== StockIdentifierType::NONE && $request->hasData('name1')) { + $hsCode = null; + foreach ($types as $type) { + if ($type->name === 'has_code') { + $hsCode = $type; + + break; + } + } + + $nameString = $request->getDataString('name1') . ' ' . ($request->getDataString('name2') ?? ''); + $names = \explode(' ', $nameString); + + $con = new \phpOMS\DataStorage\Database\Connection\SQLiteConnection(['db' => 'sqlite', 'database' => __DIR__ . '/../../../phpOMS/Api/TARIC/taric.sqlite']); + $con->connect(); + + \usort($names, function (string $a, string $b) { + return \strlen($b) - \strlen($a); + }); + + $results = []; + foreach ($names as $name) { + $query = new Builder($con); + $query->bind('name', '%' . $name . '%'); + + $sql = <<raw($sql)->execute(); + if (!empty($results)) { + break; + } + } + + if ($hsCode !== null && !empty($results)) { + $internalResponse = clone $response; + $internalRequest = new HttpRequest(); + + $internalRequest->header->account = $request->header->account; + $internalRequest->setData('ref', $item->id); + $internalRequest->setData('type', $hsCode->id); + $internalRequest->setData('value', $results[0]['Goods_code']); + + $this->app->moduleManager->get('ItemManagement', 'ApiAttribute')->apiItemAttributeCreate($internalRequest, $internalResponse); + } + + $con->close(); + } + */ + + // Define prices if ($this->app->moduleManager->isActive('Billing')) { $billing = $this->app->moduleManager->get('Billing', 'ApiPrice'); @@ -310,11 +409,11 @@ final class ApiController extends Controller $this->createMediaDirForItem($item->id, $request->header->account); $path = $this->createItemDir($item); - $uploadedFiles = $request->files['item_profile_image'] ?? []; + $uploadedFiles = $request->files['profile_image'] ?? []; if (!empty($uploadedFiles)) { - /** @var \Modules\Media\Models\MediaType $profileImageType */ - $profileImageType = MediaTypeMapper::get() - ->where('name', 'item_profile_image') + /** @var \Modules\Tag\Models\Tag $profileImageType */ + $profileImageType = TagMapper::get() + ->where('name', 'profile_image') ->execute(); // upload image @@ -326,7 +425,7 @@ final class ApiController extends Controller basePath: __DIR__ . '/../../../Modules/Media/Files' . $path, virtualPath: $path, pathSettings: PathSettings::FILE_PATH, - type: $profileImageType->id, + tag: $profileImageType->id, rel: $item->id, mapper: ItemMapper::class, field: 'files' @@ -693,6 +792,23 @@ final class ApiController extends Controller return; } + // @question This kind of thing should happen in a separate function?! + $exists = ItemL11nMapper::get() + ->where('ref', $request->getDataInt('item') ?? 0) + ->where('type', $request->getDataInt('type') ?? 0) + ->where('language', $request->getDataString('language') ?? $request->header->l11n->language) + ->execute(); + + if ($exists->id > 0) { + $response->header->status = RequestStatusCode::R_400; + $this->createInvalidCreateResponse($request, $response, $val); + + return; + } + + // @todo This is always the same for every l11n. + // Create a L11n module or something similar to the Attribute module, + // where this can be done for every other module $itemL11n = $this->createItemL11nFromRequest($request); $this->createModel($request->header->account, $itemL11n, ItemL11nMapper::class, 'item_l11n', $request->getOrigin()); $this->createStandardCreateResponse($request, $response, $itemL11n); @@ -784,7 +900,7 @@ final class ApiController extends Controller basePath: __DIR__ . '/../../../Modules/Media/Files' . $path, virtualPath: $path, pathSettings: PathSettings::FILE_PATH, - type: $request->getDataInt('type'), + tag: $request->getDataInt('tag'), rel: $item->id, mapper: ItemMapper::class, field: 'files' diff --git a/Controller/BackendController.php b/Controller/BackendController.php index 48c286d..b08753f 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -30,15 +30,14 @@ use Modules\ItemManagement\Models\MaterialTypeL11nMapper; use Modules\ItemManagement\Models\MaterialTypeMapper; use Modules\ItemManagement\Models\PermissionCategory; use Modules\Media\Models\MediaMapper; -use Modules\Media\Models\MediaTypeMapper; use Modules\Organization\Models\Attribute\UnitAttributeMapper; use Modules\Organization\Models\UnitMapper; +use Modules\Tag\Models\TagMapper; use phpOMS\Account\PermissionType; use phpOMS\Asset\AssetType; use phpOMS\Contract\RenderableInterface; use phpOMS\DataStorage\Database\Query\Builder; use phpOMS\DataStorage\Database\Query\OrderType; -use phpOMS\DataStorage\Database\Query\Where; use phpOMS\Localization\ISO3166CharEnum; use phpOMS\Localization\ISO3166NameEnum; use phpOMS\Message\RequestAbstract; @@ -180,10 +179,10 @@ final class BackendController extends Controller ->with('l11n') ->with('l11n/type') ->with('files') - ->with('files/types') + ->with('files/tags') ->where('l11n/language', $response->header->l11n->language) ->where('l11n/type/title', ['name1', 'name2'], 'IN') - ->where('files/types/name', 'item_profile_image') + ->where('files/tags/name', 'profile_image') ->where('unit', [$this->app->unitId, null]) ->limit(50) ->executeGetArray(); @@ -433,7 +432,7 @@ final class BackendController extends Controller ->with('l11n/type') ->with('files')->limit(5, 'files')->sort('files/id', OrderType::DESC) ->with('notes')->limit(5, 'notes')->sort('notes/id', OrderType::DESC) - ->with('files/types') + ->with('files/tags') ->with('attributes') ->with('attributes/type') ->with('attributes/type/l11n') @@ -456,15 +455,14 @@ final class BackendController extends Controller ->on(ItemMapper::HAS_MANY['files']['table'] . '.' . ItemMapper::HAS_MANY['files']['self'], '=', ItemMapper::TABLE . '.' . ItemMapper::PRIMARYFIELD) ->leftJoin(MediaMapper::TABLE) ->on(ItemMapper::HAS_MANY['files']['table'] . '.' . ItemMapper::HAS_MANY['files']['external'], '=', MediaMapper::TABLE . '.' . MediaMapper::PRIMARYFIELD) - ->leftJoin(MediaMapper::HAS_MANY['types']['table']) - ->on(MediaMapper::TABLE . '.' . MediaMapper::PRIMARYFIELD, '=', MediaMapper::HAS_MANY['types']['table'] . '.' . MediaMapper::HAS_MANY['types']['self']) - ->leftJoin(MediaTypeMapper::TABLE) - ->on(MediaMapper::HAS_MANY['types']['table'] . '.' . MediaMapper::HAS_MANY['types']['external'], '=', MediaTypeMapper::TABLE . '.' . MediaTypeMapper::PRIMARYFIELD) + ->leftJoin(MediaMapper::HAS_MANY['tags']['table']) + ->on(MediaMapper::TABLE . '.' . MediaMapper::PRIMARYFIELD, '=', MediaMapper::HAS_MANY['tags']['table'] . '.' . MediaMapper::HAS_MANY['tags']['self']) + ->leftJoin(TagMapper::TABLE) + ->on(MediaMapper::HAS_MANY['tags']['table'] . '.' . MediaMapper::HAS_MANY['tags']['external'], '=', TagMapper::TABLE . '.' . TagMapper::PRIMARYFIELD) ->where(ItemMapper::HAS_MANY['files']['self'], '=', $view->data['item']->id) - ->where(MediaTypeMapper::TABLE . '.' . MediaTypeMapper::getColumnByMember('name'), '=', 'item_profile_image'); + ->where(TagMapper::TABLE . '.' . TagMapper::getColumnByMember('name'), '=', 'profile_image'); $view->data['itemImage'] = MediaMapper::get() - ->with('types') ->where('id', $results) ->limit(1) ->execute(); @@ -664,7 +662,7 @@ final class BackendController extends Controller $head->addAsset(AssetType::CSS, 'Resources/chartjs/chart.css?v=' . $this->app->version); $head->addAsset(AssetType::JSLATE, 'Resources/chartjs/chart.js?v=' . $this->app->version, ['nonce' => $nonce]); - $head->addAsset(AssetType::JSLATE, 'Modules/Sales/Controller/Controller.js?v=' . self::VERSION, ['nonce' => $nonce, 'type' => 'module']); + $head->addAsset(AssetType::JSLATE, 'Modules/ItemManagement/Controller.js?v=' . self::VERSION, ['nonce' => $nonce, 'type' => 'module']); $view = new View($this->app->l11nManager, $request, $response); $view->setTemplate('/Modules/ItemManagement/Theme/Backend/item-analysis'); diff --git a/Models/Attribute/ItemAttributeTypeMapper.php b/Models/Attribute/ItemAttributeTypeMapper.php index 6c364e5..c9872b8 100644 --- a/Models/Attribute/ItemAttributeTypeMapper.php +++ b/Models/Attribute/ItemAttributeTypeMapper.php @@ -42,7 +42,7 @@ final class ItemAttributeTypeMapper extends DataMapperFactory 'itemmgmt_attr_type_datatype' => ['name' => 'itemmgmt_attr_type_datatype', 'type' => 'int', 'internal' => 'datatype'], '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_repeatable' => ['name' => 'itemmgmt_attr_type_repeatable', 'type' => 'bool', 'internal' => 'repeatable'], + 'itemmgmt_attr_type_repeatable' => ['name' => 'itemmgmt_attr_type_repeatable', 'type' => 'bool', 'internal' => 'isRepeatable'], 'itemmgmt_attr_type_internal' => ['name' => 'itemmgmt_attr_type_internal', 'type' => 'bool', 'internal' => 'isInternal'], 'itemmgmt_attr_type_pattern' => ['name' => 'itemmgmt_attr_type_pattern', 'type' => 'string', 'internal' => 'validationPattern'], 'itemmgmt_attr_type_required' => ['name' => 'itemmgmt_attr_type_required', 'type' => 'bool', 'internal' => 'isRequired'], diff --git a/Models/ItemMapper.php b/Models/ItemMapper.php index 08c75df..314e5c8 100755 --- a/Models/ItemMapper.php +++ b/Models/ItemMapper.php @@ -18,7 +18,6 @@ use Modules\Editor\Models\EditorDocMapper; use Modules\ItemManagement\Models\Attribute\ItemAttributeMapper; use Modules\Media\Models\Media; use Modules\Media\Models\MediaMapper; -use Modules\Media\Models\MediaType; use phpOMS\DataStorage\Database\Mapper\DataMapperFactory; use phpOMS\Localization\BaseStringL11n; use phpOMS\Localization\BaseStringL11nType; @@ -130,13 +129,13 @@ final class ItemMapper extends DataMapperFactory itemmgmt_item.itemmgmt_item_salesprice, media.media_id, media.media_file, - media_type.media_type_id, - media_type.media_type_name + tag.tag_id, + tag.tag_name from itemmgmt_item left join itemmgmt_item_media on itemmgmt_item.itemmgmt_item_id = itemmgmt_item_media.itemmgmt_item_media_item left join media on itemmgmt_item_media.itemmgmt_item_media_media = media.media_id - left join media_type_rel on media.media_id = media_type_rel.media_type_rel_src - left join media_type on media_type_rel.media_type_rel_dst = media_type.media_type_id and media_type.media_type_name = 'item_profile_image' + left join media_tag on media.media_id = media_tag.media_tag_src + left join tag on media_tag.media_tag_dst = tag.tag_id and tag.tag_name = 'profile_image' SQL; $q = self::$db->con->query($query); @@ -150,10 +149,6 @@ final class ItemMapper extends DataMapperFactory foreach ($itemsResult as $res) { $media = null; if ($res['media_id'] !== null) { - $mediaType = new MediaType(); - $mediaType->id = $res['media_type_id']; - $mediaType->name = $res['media_type_name']; - $media = new Media(); $media->id = $res['media_id']; $media->setPath($res['media_file']); diff --git a/Theme/Backend/item-list.tpl.php b/Theme/Backend/item-list.tpl.php index 2db5f60..70d6cdd 100755 --- a/Theme/Backend/item-list.tpl.php +++ b/Theme/Backend/item-list.tpl.php @@ -119,7 +119,7 @@ echo $this->data['nav']->render(); ?> $value) : ++$count; $url = UriFactory::build('{/base}/item/view?{?}&id=' . $value->id); - $image = $value->getFileByTypeName('item_profile_image'); + $image = $value->getFileByTagName('profile_image'); ?> <?= $this->getHtml('IMG_alt_item'); ?>data['nav']->render(); foreach ($item->files as $file) : ++$count; $url = UriFactory::build('{/base}/media/view?{?}&id=' . $file->id); - $extensionType = FileUtils::getExtensionType($value->extension); + $extensionType = FileUtils::getExtensionType($file->extension); ?> > @@ -1472,7 +1472,7 @@ echo $this->data['nav']->render();
-
+
getHtml('Logs', 'Auditor'); ?>download
@@ -1525,7 +1525,7 @@ echo $this->data['nav']->render(); getHtml('Next', '0', '0'); ?> --> - + diff --git a/info.json b/info.json index f84a4d8..c3892a5 100755 --- a/info.json +++ b/info.json @@ -24,6 +24,7 @@ "Navigation": "*", "Editor": "*", "Media": "*", + "Tag": "*", "Admin": "*" }, "load": [ diff --git a/tests/Controller/Api/ApiControllerItemTrait.php b/tests/Controller/Api/ApiControllerItemTrait.php index 2d179e0..0bdcfba 100755 --- a/tests/Controller/Api/ApiControllerItemTrait.php +++ b/tests/Controller/Api/ApiControllerItemTrait.php @@ -14,7 +14,7 @@ declare(strict_types=1); namespace Modules\ItemManagement\tests\Controller\Api; -use Modules\Media\Models\MediaTypeMapper; +use Modules\Tag\Models\TagMapper; use phpOMS\Message\Http\HttpRequest; use phpOMS\Message\Http\HttpResponse; use phpOMS\Message\Http\RequestStatusCode; @@ -79,14 +79,14 @@ trait ApiControllerItemTrait \copy(__DIR__ . '/m_icon.png', __DIR__ . '/m_icon_tmp.png'); - $profileImageType = MediaTypeMapper::get() - ->where('name', 'item_profile_image') + $profileImageType = TagMapper::get() + ->where('name', 'profile_image') ->execute(); $request->header->account = 1; $request->setData('name', '123456 backend'); $request->setData('item', 1); - $request->setData('type', $profileImageType->id); + $request->setData('tag', $profileImageType->id); TestUtils::setMember($request, 'files', [ 'file1' => [