mirror of
https://github.com/OpenXE-org/OpenXE.git
synced 2024-11-14 03:57:15 +01:00
Matrixproducts first beta
This commit is contained in:
parent
042a64589b
commit
a0d4cd1ff3
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@ conf/user.inc.php
|
||||
conf/user_defined.php
|
||||
userdata
|
||||
www/cache/
|
||||
node_modules/
|
||||
|
@ -1,4 +1,10 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Xentral ERP Software GmbH, Fuggerstrasse 11, D-86150 Augsburg
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
*/
|
||||
|
||||
namespace Xentral\Components\Http;
|
||||
|
||||
@ -9,8 +15,8 @@ class JsonResponse extends Response
|
||||
{
|
||||
/**
|
||||
* @param array|JsonSerializable $data
|
||||
* @param int $statusCode
|
||||
* @param array $headers
|
||||
* @param int $statusCode
|
||||
* @param array $headers
|
||||
*/
|
||||
public function __construct($data = [], $statusCode = self::HTTP_OK, array $headers = [])
|
||||
{
|
||||
@ -29,4 +35,19 @@ class JsonResponse extends Response
|
||||
|
||||
parent::__construct($content, $statusCode, $headers);
|
||||
}
|
||||
|
||||
public static function NoContent(array $headers = []): JsonResponse
|
||||
{
|
||||
return new JsonResponse([], Response::HTTP_NO_CONTENT, $headers);
|
||||
}
|
||||
|
||||
public static function BadRequest(array|JsonSerializable $data = [], array $headers = []): JsonResponse
|
||||
{
|
||||
return new JsonResponse($data, Response::HTTP_BAD_REQUEST, $headers);
|
||||
}
|
||||
|
||||
public static function NotFound(array|JsonSerializable $data = [], array $headers = []): JsonResponse
|
||||
{
|
||||
return new JsonResponse($data, Response::HTTP_NOT_FOUND, $headers);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,9 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
* SPDX-FileCopyrightText: 2019 Xentral ERP Software GmbH, Fuggerstrasse 11, D-86150 Augsburg
|
||||
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
*/
|
||||
|
||||
namespace Xentral\Components\Http;
|
||||
|
||||
@ -488,6 +493,16 @@ class Request
|
||||
return !empty($this->content) ? $this->content : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JSON request body as php object
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function getJson() : object
|
||||
{
|
||||
return json_decode($this->getContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content type of the request.
|
||||
*
|
||||
|
@ -1,4 +1,9 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
* SPDX-FileCopyrightText: 2019 Xentral (c) Xentral ERP Software GmbH, Fuggerstrasse 11, D-86150 Augsburg, Germany
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
namespace Xentral\Modules\Article\Gateway;
|
||||
|
||||
@ -346,4 +351,13 @@ final class ArticleGateway
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function SetVariantStatus(int $articleId, ?int $variantOfId) : void {
|
||||
$sql = "UPDATE artikel SET variante = :isVariant, variante_von = :variantOfId WHERE id = :articleId";
|
||||
$this->db->perform($sql, [
|
||||
'articleId' => $articleId,
|
||||
'variantOfId' => $variantOfId > 0 ? $variantOfId : null,
|
||||
'isVariant' => $variantOfId > 0
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
47
classes/Modules/MatrixProduct/Bootstrap.php
Normal file
47
classes/Modules/MatrixProduct/Bootstrap.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
*/
|
||||
|
||||
namespace Xentral\Modules\MatrixProduct;
|
||||
|
||||
use Xentral\Core\DependencyInjection\ContainerInterface;
|
||||
|
||||
final class Bootstrap
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function registerServices()
|
||||
{
|
||||
return [
|
||||
'MatrixProductService' => 'onInitMatrixProductService',
|
||||
'MatrixProductGateway' => 'onInitMatrixProductGateway',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return MatrixProductService
|
||||
*/
|
||||
public static function onInitMatrixProductService(ContainerInterface $container) : MatrixProductService
|
||||
{
|
||||
return new MatrixProductService(
|
||||
$container->get('Database'),
|
||||
$container->get('MatrixProductGateway'),
|
||||
$container->get('ArticleGateway')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return MatrixProductGateway
|
||||
*/
|
||||
public static function onInitMatrixProductGateway(ContainerInterface $container) : MatrixProductGateway
|
||||
{
|
||||
return new MatrixProductGateway($container->get('Database'));
|
||||
}
|
||||
}
|
34
classes/Modules/MatrixProduct/Data/Group.php
Normal file
34
classes/Modules/MatrixProduct/Data/Group.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
namespace Xentral\Modules\MatrixProduct\Data;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
final class Group implements JsonSerializable
|
||||
{
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public ?int $id = null,
|
||||
public bool $active = true,
|
||||
public ?string $nameExternal = null,
|
||||
public int $projectId = 0,
|
||||
public bool $required = false,
|
||||
public ?int $articleId = null,
|
||||
public int $sort = 0
|
||||
)
|
||||
{ }
|
||||
|
||||
public static function fromDbArray(array $data) : self {
|
||||
return new self($data['name'], $data['id'], $data['aktiv'], $data['name_ext'], $data['projekt'], $data['pflicht'],
|
||||
$data['artikel'] ?? null, $data['sort'] ?? 0);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return (array) $this;
|
||||
}
|
||||
}
|
38
classes/Modules/MatrixProduct/Data/Option.php
Normal file
38
classes/Modules/MatrixProduct/Data/Option.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
namespace Xentral\Modules\MatrixProduct\Data;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
final class Option implements JsonSerializable
|
||||
{
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public readonly int $groupId,
|
||||
public ?int $id = null,
|
||||
public bool $active = true,
|
||||
public string $nameExternal = '',
|
||||
public int $sort = 0,
|
||||
public string $articleNumber = '',
|
||||
public string $articleNumberSuffix = '',
|
||||
public readonly ?int $globalOptionId = null,
|
||||
public readonly ?int $articleId = null
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public static function fromDbArray(array $data) : Option {
|
||||
return new self($data['name'], $data['gruppe'], $data['id'], $data['aktiv'], $data['name_ext'], $data['sort'],
|
||||
$data['artikelnummer'], $data['articlenumber_suffix'], $data['matrixprodukt_eigenschaftenoptionen'] ?? null,
|
||||
$data['artikel'] ?? null);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return (array) $this;
|
||||
}
|
||||
}
|
278
classes/Modules/MatrixProduct/MatrixProductGateway.php
Normal file
278
classes/Modules/MatrixProduct/MatrixProductGateway.php
Normal file
@ -0,0 +1,278 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
*/
|
||||
|
||||
namespace Xentral\Modules\MatrixProduct;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\MatrixProduct\Data\Group;
|
||||
use Xentral\Modules\MatrixProduct\Data\Option;
|
||||
|
||||
final class MatrixProductGateway
|
||||
{
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(private readonly Database $db)
|
||||
{
|
||||
}
|
||||
|
||||
//region Groups
|
||||
public function GetGlobalGroupById(int $id) : Group {
|
||||
$sql = "SELECT * FROM matrixprodukt_eigenschaftengruppen WHERE id = :id";
|
||||
$res = $this->db->fetchRow($sql, ['id' => $id]);
|
||||
return Group::fromDbArray($res);
|
||||
}
|
||||
|
||||
public function GetArticleGroupById(int $id) : Group {
|
||||
$sql = "SELECT * FROM matrixprodukt_eigenschaftengruppen_artikel WHERE id = :id";
|
||||
$res = $this->db->fetchRow($sql, ['id' => $id]);
|
||||
return Group::fromDbArray($res);
|
||||
}
|
||||
|
||||
public function GetArticleGroupIdByName(int $articleId, string $name) : int {
|
||||
$sql = "SELECT id FROM matrixprodukt_eigenschaftengruppen_artikel
|
||||
WHERE name = :name AND artikel = :articleId";
|
||||
return $this->db->fetchValue($sql, [
|
||||
'name' => $name,
|
||||
'articleId' => $articleId
|
||||
]);
|
||||
}
|
||||
|
||||
public function GetArticleGroupsByArticleId(int $articleId) : array {
|
||||
$sql = "SELECT * FROM matrixprodukt_eigenschaftengruppen_artikel WHERE artikel = :articleId";
|
||||
$rows = $this->db->fetchAssoc($sql, ['articleId' => $articleId]);
|
||||
$res = [];
|
||||
foreach ($rows as $row) {
|
||||
$res[] = Group::fromDbArray($row);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function InsertGlobalGroup(Group $obj) : Group {
|
||||
$sql = "INSERT INTO matrixprodukt_eigenschaftengruppen
|
||||
(aktiv, name, name_ext, projekt, pflicht)
|
||||
VALUES
|
||||
(:active, :name, :nameExternal, :projectId, :required)";
|
||||
print_r($obj);
|
||||
$this->db->perform($sql, (array)$obj);
|
||||
$obj->id = $this->db->lastInsertId();
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function InsertArticleGroup(Group $obj) : Group {
|
||||
$sql = "INSERT INTO matrixprodukt_eigenschaftengruppen_artikel
|
||||
(artikel, aktiv, name, name_ext, projekt, sort, pflicht)
|
||||
VALUES
|
||||
(:articleId, :active, :name, :nameExternal, :projectId, :sort, :required)";
|
||||
$this->db->perform($sql, (array)$obj);
|
||||
$obj->id = $this->db->lastInsertId();
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function UpdateGlobalGroup(Group $obj) : Group {
|
||||
$sql = "UPDATE matrixprodukt_eigenschaftengruppen
|
||||
SET aktiv = :active, name = :name, name_ext = :nameExternal, projekt = :projectId, pflicht = :required
|
||||
WHERE id = :id";
|
||||
$this->db->perform($sql, (array)$obj);
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function UpdateArticleGroup(Group $obj) : Group {
|
||||
$sql = "UPDATE matrixprodukt_eigenschaftengruppen_artikel
|
||||
SET aktiv = :active, name = :name, name_ext = :nameExternal, projekt = :projectId, sort = :sort, pflicht = :required
|
||||
WHERE id = :id";
|
||||
$this->db->perform($sql, (array)$obj);
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function DeleteGlobalGroup(int $id) : void {
|
||||
$sql = "UPDATE matrixprodukt_eigenschaftenoptionen_artikel moa
|
||||
JOIN matrixprodukt_eigenschaftenoptionen mo ON moa.matrixprodukt_eigenschaftenoptionen=mo.id
|
||||
JOIN matrixprodukt_eigenschaftengruppen mg ON mo.gruppe=mg.id
|
||||
SET moa.matrixprodukt_eigenschaftenoptionen=0
|
||||
WHERE mg.id = :id";
|
||||
$this->db->perform($sql, ['id' => $id]);
|
||||
$sql = "DELETE mg, mo
|
||||
FROM matrixprodukt_eigenschaftengruppen mg
|
||||
LEFT OUTER JOIN matrixprodukt_eigenschaftenoptionen mo ON mo.gruppe = mg.id
|
||||
WHERE mg.id = :id";
|
||||
$this->db->perform($sql, ['id' => $id]);
|
||||
}
|
||||
|
||||
public function DeleteArticleGroup(int $id) : void {
|
||||
$sql = "DELETE mga, moa, mota
|
||||
FROM matrixprodukt_eigenschaftengruppen_artikel mga
|
||||
LEFT OUTER JOIN matrixprodukt_eigenschaftenoptionen_artikel moa ON moa.gruppe = mga.id
|
||||
LEFT OUTER JOIN matrixprodukt_optionen_zu_artikel mota ON mota.option_id = moa.id
|
||||
WHERE mga.id = :id";
|
||||
$this->db->perform($sql, ['id' => $id]);
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Options
|
||||
public function GetGlobalOptionById(int $id) : Option {
|
||||
$sql = "SELECT * FROM matrixprodukt_eigenschaftenoptionen WHERE id = :id";
|
||||
$res = $this->db->fetchRow($sql, ['id' => $id]);
|
||||
return Option::fromDbArray($res);
|
||||
}
|
||||
|
||||
public function GetArticleOptionById(int $id) : Option {
|
||||
$sql = "SELECT * FROM matrixprodukt_eigenschaftenoptionen_artikel WHERE id = :id";
|
||||
$res = $this->db->fetchRow($sql, ['id' => $id]);
|
||||
return Option::fromDbArray($res);
|
||||
}
|
||||
|
||||
public function GetArticleOptionIdsByGroupIds(int|array $groupIds) : array {
|
||||
$sql = "SELECT id FROM matrixprodukt_eigenschaftenoptionen WHERE gruppe IN (:ids)";
|
||||
return $this->db->fetchCol($sql, ['ids' => $groupIds]);
|
||||
}
|
||||
|
||||
public function GetArticleOptionIdByName(int $articleId, int $groupId, string $name) : int {
|
||||
$sql = "SELECT id FROM matrixprodukt_eigenschaftenoptionen_artikel
|
||||
WHERE name = :name AND artikel = :articleId AND gruppe = :groupId";
|
||||
return $this->db->fetchValue($sql, [
|
||||
'name' => $name,
|
||||
'articleId' => $articleId,
|
||||
'groupId' => $groupId
|
||||
]);
|
||||
}
|
||||
|
||||
public function GetArticleOptionsByArticleId(int $articleId) : array {
|
||||
$sql = "SELECT * FROM matrixprodukt_eigenschaftenoptionen_artikel WHERE artikel = :articleId";
|
||||
$rows = $this->db->fetchAssoc($sql, ['articleId' => $articleId]);
|
||||
$res = [];
|
||||
foreach ($rows as $row) {
|
||||
$res[] = Option::fromDbArray($row);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function GetSelectedOptionIdsByVariantId(int $variantId) : array {
|
||||
$sql = "SELECT option_id FROM matrixprodukt_optionen_zu_artikel WHERE artikel = :variantId";
|
||||
return $this->db->fetchCol($sql, ['variantId' => $variantId]);
|
||||
}
|
||||
|
||||
public function InsertGlobalOption(Option $obj) : Option {
|
||||
$sql = "INSERT INTO matrixprodukt_eigenschaftenoptionen
|
||||
(aktiv, name, name_ext, sort, gruppe, artikelnummer, articlenumber_suffix)
|
||||
VALUES
|
||||
(:active, :name, :nameExternal, :sort, :groupId, :articleNumber, :articleNumberSuffix)";
|
||||
$this->db->perform($sql, (array)$obj);
|
||||
$obj->id = $this->db->lastInsertId();
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function InsertArticleOption(Option $obj) : Option {
|
||||
$sql = "INSERT INTO matrixprodukt_eigenschaftenoptionen_artikel
|
||||
(artikel, matrixprodukt_eigenschaftenoptionen, aktiv, name, name_ext, sort, gruppe, artikelnummer, articlenumber_suffix)
|
||||
VALUES
|
||||
(:articleId, :globalOptionId, :active, :name, :nameExternal, :sort, :groupId, :articleNumber, :articleNumberSuffix)";
|
||||
$this->db->perform($sql, (array)$obj);
|
||||
$obj->id = $this->db->lastInsertId();
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function UpdateGlobalOption(Option $obj) : Option {
|
||||
$sql = "UPDATE matrixprodukt_eigenschaftenoptionen
|
||||
SET aktiv = :active, name = :name, name_ext = :nameExternal, sort = :sort, artikelnummer = :articleNumber,
|
||||
articlenumber_suffix = :articleNumberSuffix
|
||||
WHERE id = :id";
|
||||
$this->db->perform($sql, (array)$obj);
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function UpdateArticleOption(Option $obj) : Option {
|
||||
$sql = "UPDATE matrixprodukt_eigenschaftenoptionen_artikel
|
||||
SET aktiv = :active, name = :name, name_ext = :nameExternal, sort = :sort, artikelnummer = :articleNumber,
|
||||
articlenumber_suffix = :articleNumberSuffix
|
||||
WHERE id = :id";
|
||||
$this->db->perform($sql, (array)$obj);
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function DeleteGlobalOption(int $id) : void {
|
||||
$sql = "UPDATE matrixprodukt_eigenschaftenoptionen_artikel moa
|
||||
JOIN matrixprodukt_eigenschaftenoptionen mo ON moa.matrixprodukt_eigenschaftenoptionen=mo.id
|
||||
SET moa.matrixprodukt_eigenschaftenoptionen=0
|
||||
WHERE mo.id = :id";
|
||||
$this->db->perform($sql, ['id' => $id]);
|
||||
$sql = "DELETE moa
|
||||
FROM matrixprodukt_eigenschaftenoptionen mo
|
||||
WHERE mo.id = :id";
|
||||
$this->db->perform($sql, ['id' => $id]);
|
||||
}
|
||||
|
||||
public function DeleteArticleOption(int $id) : void {
|
||||
$sql = "DELETE moa, mota
|
||||
FROM matrixprodukt_eigenschaftenoptionen_artikel moa
|
||||
LEFT OUTER JOIN matrixprodukt_optionen_zu_artikel mota ON mota.option_id=moa.id
|
||||
WHERE moa.id = :id";
|
||||
$this->db->perform($sql, ['id' => $id]);
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Variants
|
||||
public function ReplaceVariant(int $oldId, int $newId) : void {
|
||||
$sql = "UPDATE matrixprodukt_optionen_zu_artikel SET artikel = :newId WHERE artikel = :oldId";
|
||||
$this->db->perform($sql, [
|
||||
'oldId' => $oldId,
|
||||
'newId' => $newId]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $variantId
|
||||
* @return int[]
|
||||
*/
|
||||
public function GetOptionIdsByVariant(int $variantId) : array {
|
||||
$sql = "SELECT option_id FROM matrixprodukt_optionen_zu_artikel WHERE artikel = :id";
|
||||
return $this->db->fetchCol($sql, ['id' => $variantId]);
|
||||
}
|
||||
|
||||
public function AddOptionToVariant(int $variantId, int $optionId) : void {
|
||||
$sql = "INSERT INTO matrixprodukt_optionen_zu_artikel (artikel, option_id) VALUES (:variantId, :optionId)";
|
||||
$this->db->perform($sql, [
|
||||
'variantId' => $variantId,
|
||||
'optionId' => $optionId
|
||||
]);
|
||||
}
|
||||
|
||||
public function DeleteOptionFromVariant(int $variantId, int $optionId) : void {
|
||||
$sql = "DELETE FROM matrixprodukt_optionen_zu_artikel WHERE artikel = :variantId AND option_id = :optionId";
|
||||
$this->db->perform($sql, [
|
||||
'variantId' => $variantId,
|
||||
'optionId' => $optionId
|
||||
]);
|
||||
}
|
||||
|
||||
public function GetVariantIdByOptions(array $optionIds) : ?int {
|
||||
if (empty($optionIds))
|
||||
return null;
|
||||
sort($optionIds);
|
||||
$sql = "SELECT artikel
|
||||
FROM matrixprodukt_optionen_zu_artikel
|
||||
WHERE option_id IN (:ids)
|
||||
GROUP BY artikel
|
||||
HAVING group_concat(option_id order by option_id separator ',') = :idList";
|
||||
$res = $this->db->fetchValue($sql, [
|
||||
'ids' => $optionIds,
|
||||
'idList' => join(',', $optionIds)
|
||||
]);
|
||||
return $res ?: null;
|
||||
}
|
||||
|
||||
public function GetVariantIdsByOptions(int|array $optionIds) : array
|
||||
{
|
||||
$sql = "SELECT artikel FROM matrixprodukt_optionen_zu_artikel WHERE option_id IN (:ids)";
|
||||
return $this->db->fetchCol($sql, ['ids' => $optionIds]);
|
||||
}
|
||||
|
||||
public function DeleteVariantById(int $variantId) : void {
|
||||
$sql = "DELETE FROM matrixprodukt_optionen_zu_artikel WHERE artikel = :id";
|
||||
$this->db->perform($sql, ['id' => $variantId]);
|
||||
}
|
||||
//endregion
|
||||
}
|
170
classes/Modules/MatrixProduct/MatrixProductService.php
Normal file
170
classes/Modules/MatrixProduct/MatrixProductService.php
Normal file
@ -0,0 +1,170 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
*/
|
||||
|
||||
namespace Xentral\Modules\MatrixProduct;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Article\Gateway\ArticleGateway;
|
||||
use Xentral\Modules\MatrixProduct\Data\Option;
|
||||
use Xentral\Modules\MatrixProduct\Data\Group;
|
||||
|
||||
final class MatrixProductService
|
||||
{
|
||||
/**
|
||||
* @param Database $db
|
||||
* @param MatrixProductGateway $gateway
|
||||
* @param ArticleGateway $articleGateway
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly Database $db,
|
||||
private readonly MatrixProductGateway $gateway,
|
||||
private readonly ArticleGateway $articleGateway)
|
||||
{ }
|
||||
|
||||
//region Groups
|
||||
public function GetGlobalGroupById(int $id) : Group {
|
||||
return $this->gateway->GetGlobalGroupById($id);
|
||||
}
|
||||
|
||||
public function GetArticleGroupById(int $id) : Group {
|
||||
return $this->gateway->GetArticleGroupById($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
* @return Group[]
|
||||
*/
|
||||
public function GetArticleGroupsByArticleId(int $articleId) : array {
|
||||
return $this->gateway->GetArticleGroupsByArticleId($articleId);
|
||||
}
|
||||
|
||||
public function SaveGlobalGroup(Group $obj) : void {
|
||||
if ($obj->id > 0)
|
||||
$this->gateway->UpdateGlobalGroup($obj);
|
||||
else
|
||||
$this->gateway->InsertGlobalGroup($obj);
|
||||
}
|
||||
|
||||
public function SaveArticleGroup(Group $obj) : void {
|
||||
if ($obj->id > 0) {
|
||||
$this->gateway->UpdateArticleGroup($obj);
|
||||
} else {
|
||||
$this->gateway->InsertArticleGroup($obj);
|
||||
}
|
||||
}
|
||||
|
||||
public function DeleteGlobalGroup(int $id) : void {
|
||||
$this->gateway->DeleteGlobalGroup($id);
|
||||
}
|
||||
|
||||
public function DeleteArticleGroup(int $id) : bool {
|
||||
$options = $this->gateway->GetArticleOptionIdsByGroupIds($id);
|
||||
$variants = $this->gateway->GetVariantIdsByOptions($options);
|
||||
if (!empty($variants))
|
||||
return false;
|
||||
$this->gateway->DeleteArticleGroup($id);
|
||||
return true;
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Options
|
||||
public function GetGlobalOptionById(int $id) : Option {
|
||||
return $this->gateway->GetGlobalOptionById($id);
|
||||
}
|
||||
|
||||
public function GetArticleOptionById(int $id) : Option {
|
||||
return $this->gateway->GetArticleOptionById($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $articleId
|
||||
* @return Option[]
|
||||
*/
|
||||
public function GetArticleOptionsByArticleId(int $articleId) : array {
|
||||
return $this->gateway->GetArticleOptionsByArticleId($articleId);
|
||||
}
|
||||
|
||||
public function GetSelectedOptionIdsByVariantId(int $variantId) : array {
|
||||
return $this->gateway->GetSelectedOptionIdsByVariantId($variantId);
|
||||
}
|
||||
|
||||
public function SaveGlobalOption(Option $obj) : void {
|
||||
if ($obj->id > 0) {
|
||||
$this->gateway->UpdateGlobalOption($obj);
|
||||
} else {
|
||||
$this->gateway->InsertGlobalOption($obj);
|
||||
}
|
||||
}
|
||||
|
||||
public function SaveArticleOption(Option $obj) : void {
|
||||
if ($obj->id > 0) {
|
||||
$this->gateway->UpdateArticleOption($obj);
|
||||
} else {
|
||||
$this->gateway->InsertArticleOption($obj);
|
||||
}
|
||||
}
|
||||
|
||||
public function DeleteGlobalOption(int $id) : void {
|
||||
$this->gateway->DeleteGlobalOption($id);
|
||||
}
|
||||
|
||||
public function DeleteArticleOption(int $id) : bool {
|
||||
$variants = $this->gateway->GetVariantIdsByOptions($id);
|
||||
if (!empty($variants))
|
||||
return false;
|
||||
$this->gateway->DeleteArticleOption($id);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function AddGlobalOptionsForArticle(int $articleId, int|array $optionIds): void
|
||||
{
|
||||
$sql = "SELECT mg.name groupname, mg.name_ext groupnameext, mg.projekt as groupprojekt, mg.pflicht as grouprequired, mo.*
|
||||
FROM matrixprodukt_eigenschaftenoptionen mo
|
||||
JOIN matrixprodukt_eigenschaftengruppen mg on mo.gruppe=mg.id
|
||||
WHERE mo.id IN (:optionIds)";
|
||||
$optionArr = $this->db->fetchAll($sql, ['optionIds' => $optionIds]);
|
||||
foreach ($optionArr as $option) {
|
||||
$groupId = $this->gateway->GetArticleGroupIdByName($articleId, $option['groupname']);
|
||||
if (!$groupId) {
|
||||
$obj = new Group($option['groupname'], nameExternal: $option['groupnameext'], projectId: $option['groupprojekt'], required: $option['grouprequired'], articleId: $articleId);
|
||||
$group = $this->gateway->InsertArticleGroup($obj);
|
||||
$groupId = $group->id;
|
||||
}
|
||||
$optionId = $this->gateway->GetArticleOptionIdByName($articleId, $groupId, $option['name']);
|
||||
if (!$optionId) {
|
||||
$obj = new Option($option['name'], $groupId, nameExternal: $option['name_ext'], sort: $option['sort'], globalOptionId: $option['id'], articleId: $articleId);
|
||||
$this->gateway->InsertArticleOption($obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Variants
|
||||
public function SaveVariant(int $articleId, int $variantId, array $optionIds, ?int $oldVariantId = null) : bool|string {
|
||||
if ($oldVariantId != null && $oldVariantId != $variantId) {
|
||||
$this->gateway->ReplaceVariant($oldVariantId, $variantId);
|
||||
$this->articleGateway->SetVariantStatus($oldVariantId, null);
|
||||
}
|
||||
$variantWithOptionSet = $this->gateway->GetVariantIdByOptions($optionIds);
|
||||
if ($variantWithOptionSet != null && $variantWithOptionSet != $variantId)
|
||||
return 'Diese Optionen wurden bereits einer anderen Variante zugewiesen';
|
||||
|
||||
$existingIds = $this->gateway->GetOptionIdsByVariant($variantId);
|
||||
$toDelete = array_diff($existingIds, $optionIds);
|
||||
$toCreate = array_diff($optionIds, $existingIds);
|
||||
foreach ($toDelete as $item)
|
||||
$this->gateway->DeleteOptionFromVariant($variantId, $item);
|
||||
foreach ($toCreate as $item)
|
||||
$this->gateway->AddOptionToVariant($variantId, $item);
|
||||
$this->articleGateway->SetVariantStatus($variantId, $articleId);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function DeleteVariant(int $variantId) : void {
|
||||
$this->gateway->DeleteVariantById($variantId);
|
||||
}
|
||||
//endregion
|
||||
}
|
55
classes/Modules/MatrixProduct/www/js/AddGlobalToArticle.vue
Normal file
55
classes/Modules/MatrixProduct/www/js/AddGlobalToArticle.vue
Normal file
@ -0,0 +1,55 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
-->
|
||||
|
||||
<script setup>
|
||||
import {ref, onMounted} from "vue";
|
||||
import axios from "axios";
|
||||
import Dialog from "primevue/dialog";
|
||||
import Listbox from "primevue/listbox";
|
||||
import Button from "primevue/button";
|
||||
import {AlertErrorHandler} from '@res/js/ajaxErrorHandler';
|
||||
|
||||
const props = defineProps({
|
||||
articleId: String
|
||||
})
|
||||
const emit = defineEmits(['save', 'close']);
|
||||
|
||||
const model = ref(null);
|
||||
const group = ref(null);
|
||||
const selected = ref([]);
|
||||
onMounted(async () => {
|
||||
model.value = await fetch('index.php?module=matrixprodukt&action=list&cmd=selectoptions')
|
||||
.then(x => x.json())
|
||||
})
|
||||
async function save() {
|
||||
await axios.post('index.php?module=matrixprodukt&action=artikel&cmd=addoptions', {
|
||||
articleId: props.articleId,
|
||||
optionIds: selected.value
|
||||
})
|
||||
.then(() => {emit('save')})
|
||||
.catch(AlertErrorHandler);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog visible modal header="Globale Optionen hinzufügen" style="width: 500px" @update:visible="emit('close')">
|
||||
<div v-if="model" class="grid gap-1" style="grid-template-columns: 25% 75%">
|
||||
<label for="matrixProductOptions" style="padding-top: 5px;">Optionen:</label>
|
||||
<Listbox multiple
|
||||
:options="model"
|
||||
optionGroupLabel="name"
|
||||
optionGroupChildren="options"
|
||||
optionLabel="name"
|
||||
optionValue="id"
|
||||
listStyle="height: 200px"
|
||||
v-model="selected" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<Button label="ABBRECHEN" @click="emit('close')" />
|
||||
<Button label="HINZUFÜGEN" @click="save" :disabled="selected.length === 0"/>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
70
classes/Modules/MatrixProduct/www/js/App.vue
Normal file
70
classes/Modules/MatrixProduct/www/js/App.vue
Normal file
@ -0,0 +1,70 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
-->
|
||||
|
||||
<script setup>
|
||||
import axios from "axios";
|
||||
import {ref} from 'vue';
|
||||
import {reloadDataTables} from "@res/js/jqueryBridge";
|
||||
import AddGlobalToArticle from "./AddGlobalToArticle.vue";
|
||||
import GroupEdit from "./GroupEdit.vue";
|
||||
import OptionEdit from "./OptionEdit.vue";
|
||||
import Variant from "./Variant.vue";
|
||||
|
||||
const model = ref(null);
|
||||
|
||||
document.getElementById('main').addEventListener('click', async (ev) => {
|
||||
const target = ev.target;
|
||||
if (!target || !target.classList.contains('vueAction'))
|
||||
return;
|
||||
const ds = target.dataset;
|
||||
if (ds.action.endsWith('Delete')) {
|
||||
const cnf = confirm('Wirklich löschen?');
|
||||
if (!cnf)
|
||||
return;
|
||||
let url;
|
||||
switch (ds.action) {
|
||||
case 'groupDelete':
|
||||
url = ds.articleId > 0
|
||||
? 'index.php?module=matrixprodukt&action=artikel&cmd=groupdelete'
|
||||
: 'index.php?module=matrixprodukt&action=list&cmd=delete';
|
||||
await axios.post(url, {groupId: ds.groupId});
|
||||
break;
|
||||
case 'optionDelete':
|
||||
url = ds.articleId > 0
|
||||
? 'index.php?module=matrixprodukt&action=artikel&cmd=optiondelete'
|
||||
: 'index.php?module=matrixprodukt&action=optionenlist&cmd=delete';
|
||||
await axios.post(url, {optionId: ds.optionId});
|
||||
break;
|
||||
case 'variantDelete':
|
||||
url = 'index.php?module=matrixprodukt&action=artikel&cmd=variantdelete';
|
||||
await axios.post(url, {variantId: ds.variantId});
|
||||
break;
|
||||
}
|
||||
onSave();
|
||||
return;
|
||||
}
|
||||
|
||||
model.value = ds;
|
||||
});
|
||||
|
||||
function onSave() {
|
||||
reloadDataTables();
|
||||
onClose();
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
model.value = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="model">
|
||||
<AddGlobalToArticle v-if="model.action === 'addGlobalToArticle'" v-bind="model" @close="onClose" @save="onSave" />
|
||||
<GroupEdit v-else-if="model.action === 'groupEdit'" v-bind="model" @close="onClose" @save="onSave" />
|
||||
<OptionEdit v-else-if="model.action === 'optionEdit'" v-bind="model" @close="onClose" @save="onSave" />
|
||||
<Variant v-else-if="model.action === 'variantEdit'" v-bind="model" @close="onClose" @save="onSave" />
|
||||
</template>
|
||||
</template>
|
72
classes/Modules/MatrixProduct/www/js/GroupEdit.vue
Normal file
72
classes/Modules/MatrixProduct/www/js/GroupEdit.vue
Normal file
@ -0,0 +1,72 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
-->
|
||||
|
||||
<script setup>
|
||||
import {ref, onMounted} from "vue";
|
||||
import axios from "axios";
|
||||
import Dialog from "primevue/dialog";
|
||||
import Button from "primevue/button";
|
||||
import {AlertErrorHandler} from "@res/js/ajaxErrorHandler";
|
||||
import AutoComplete from "@res/vue/AutoComplete.vue";
|
||||
|
||||
const props = defineProps({
|
||||
groupId: String,
|
||||
articleId: String
|
||||
});
|
||||
const emit = defineEmits(['save', 'close']);
|
||||
|
||||
const model = ref({});
|
||||
|
||||
onMounted(async () => {
|
||||
if (props.groupId > 0) {
|
||||
const url = props.articleId > 0
|
||||
? 'index.php?module=matrixprodukt&action=artikel&cmd=groupedit'
|
||||
: 'index.php?module=matrixprodukt&action=list&cmd=edit';
|
||||
model.value = await axios.get(url, {
|
||||
params: props
|
||||
}).then(response => response.data)
|
||||
}
|
||||
})
|
||||
|
||||
async function save() {
|
||||
if (!parseInt(props.groupId) > 0)
|
||||
model.value.groupId = 0;
|
||||
const url = props.articleId > 0
|
||||
? 'index.php?module=matrixprodukt&action=artikel&cmd=groupsave'
|
||||
: 'index.php?module=matrixprodukt&action=list&cmd=save';
|
||||
await axios.post(url, {...props, ...model.value})
|
||||
.catch(AlertErrorHandler)
|
||||
.then(() => {emit('save')});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog visible modal header="Gruppe anlegen/bearbeiten" style="width: 500px" @update:visible="emit('close')" class="p-fluid">
|
||||
<div class="grid gap-1" style="grid-template-columns: 25% 75%">
|
||||
<label for="matrixProduct_group_name">Name:</label>
|
||||
<input type="text" v-model="model.name" required />
|
||||
<label for="matrixProduct_group_nameExternal">Name Extern:</label>
|
||||
<input type="text" v-model="model.nameExternal" />
|
||||
<label for="matrixProduct_group_project">Projekt:</label>
|
||||
<AutoComplete
|
||||
v-model="model.project"
|
||||
:optionLabel="item => [item.abkuerzung, item.name].join(' ')"
|
||||
ajaxFilter="projektname"
|
||||
forceSelection
|
||||
/>
|
||||
<label v-if="articleId" for="matrixProduct_group_sort">Sortierung:</label>
|
||||
<input v-if="articleId" type="text" v-model="model.sort">
|
||||
<label for="matrixProduct_group_required">Pflicht:</label>
|
||||
<input type="checkbox" v-model="model.required" class="justify-self-start">
|
||||
<label for="matrixProduct_group_active">Aktiv:</label>
|
||||
<input type="checkbox" v-model="model.active" class="justify-self-start">
|
||||
</div>
|
||||
<template #footer>
|
||||
<Button label="ABBRECHEN" @click="emit('close')" />
|
||||
<Button label="SPEICHERN" @click="save" :disabled="!model.name"/>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
63
classes/Modules/MatrixProduct/www/js/OptionEdit.vue
Normal file
63
classes/Modules/MatrixProduct/www/js/OptionEdit.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
-->
|
||||
|
||||
<script setup>
|
||||
import {ref, onMounted} from "vue";
|
||||
import axios from "axios";
|
||||
import Button from "primevue/button";
|
||||
import Dialog from "primevue/dialog";
|
||||
import {AlertErrorHandler} from "@res/js/ajaxErrorHandler";
|
||||
|
||||
const props = defineProps({
|
||||
optionId: String,
|
||||
groupId: String,
|
||||
articleId: String
|
||||
});
|
||||
const emit = defineEmits(['save', 'close']);
|
||||
|
||||
const model = ref({});
|
||||
|
||||
onMounted(async () => {
|
||||
if (props.optionId > 0) {
|
||||
const url = props.articleId > 0
|
||||
? 'index.php?module=matrixprodukt&action=artikel&cmd=optionedit'
|
||||
: 'index.php?module=matrixprodukt&action=optionenlist&cmd=edit';
|
||||
model.value = await axios.get(url, {
|
||||
params: props
|
||||
}).then(response => response.data)
|
||||
}
|
||||
})
|
||||
|
||||
async function save() {
|
||||
const url = props.articleId > 0
|
||||
? 'index.php?module=matrixprodukt&action=artikel&cmd=optionsave'
|
||||
: 'index.php?module=matrixprodukt&action=optionenlist&cmd=save';
|
||||
await axios.post(url, {...props, ...model.value})
|
||||
.then(() => {emit('save')})
|
||||
.catch(AlertErrorHandler);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog visible modal header="Option anlegen/bearbeiten" style="width: 500px" @update:visible="emit('close')">
|
||||
<div class="grid gap-1" style="grid-template-columns: 25% 75%">
|
||||
<label for="matrixProduct_option_name">Name:</label>
|
||||
<input id="matrixProduct_option_name" type="text" v-model="model.name" required />
|
||||
<label for="matrixProduct_option_nameExternal">Name Extern:</label>
|
||||
<input id="matrixProduct_option_nameExternal" type="text" v-model="model.nameExternal" />
|
||||
<label for="matrixProduct_option_articleNumberSuffix">Artikelnummer-Suffix:</label>
|
||||
<input id="matrixProduct_option_articleNumberSuffix" type="text" v-model="model.articleNumberSuffix" />
|
||||
<label for="matrixProduct_option_sort">Sortierung:</label>
|
||||
<input id="matrixProduct_option_sort" type="text" v-model="model.sort" />
|
||||
<label for="matrixProduct_option_active">Aktiv:</label>
|
||||
<input id="matrixProduct_option_active" type="checkbox" v-model="model.active" class="justify-self-start" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<Button label="ABBRECHEN" @click="emit('close')" />
|
||||
<Button label="SPEICHERN" @click="save" :disabled="!model.name" />
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
54
classes/Modules/MatrixProduct/www/js/Variant.vue
Normal file
54
classes/Modules/MatrixProduct/www/js/Variant.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<script setup>
|
||||
import AutoComplete from "@res/vue/AutoComplete.vue";
|
||||
import Button from "primevue/button";
|
||||
import Dialog from "primevue/dialog";
|
||||
import Dropdown from "primevue/dropdown";
|
||||
import {onMounted, ref} from "vue";
|
||||
import axios from "axios";
|
||||
|
||||
const props = defineProps({
|
||||
articleId: String,
|
||||
variantId: String,
|
||||
});
|
||||
const emit = defineEmits(['save', 'close']);
|
||||
|
||||
const model = ref({});
|
||||
|
||||
onMounted(async () => {
|
||||
model.value = await axios.get('index.php?module=matrixprodukt&action=artikel&cmd=variantedit', {
|
||||
params: {...props}
|
||||
}).then(response => { return {...props, ...response.data}})
|
||||
})
|
||||
|
||||
async function save() {
|
||||
await axios.post('index.php?module=matrixprodukt&action=artikel&cmd=variantsave', {...props, ...model.value})
|
||||
.catch(error => alert(error.response.data))
|
||||
.then(() => {emit('save')});
|
||||
}
|
||||
|
||||
const buttons = {
|
||||
abbrechen: () => emit('close'),
|
||||
speichern: save
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog visible modal header="Variante" style="width: 500px" @update:visible="emit('close')">
|
||||
<div class="grid gap-1" style="grid-template-columns: 25% 75%;">
|
||||
<label>Artikel</label>
|
||||
<AutoComplete v-model="model.variant"
|
||||
:optionLabel="(item) => [item.nummer, item.name].join(' ')"
|
||||
ajax-filter="artikelnummer"
|
||||
forceSelection
|
||||
/>
|
||||
<template v-for="group in model.groups">
|
||||
<label>{{ group.name }}</label>
|
||||
<Dropdown v-model="group.selected" :options="group.options" optionLabel="name" optionValue="value" />
|
||||
</template>
|
||||
</div>
|
||||
<template #footer>
|
||||
<Button label="ABBRECHEN" @click="emit('close')" />
|
||||
<Button label="SPEICHERN" @click="save" />
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
8
classes/Modules/MatrixProduct/www/js/entry.jsx
Normal file
8
classes/Modules/MatrixProduct/www/js/entry.jsx
Normal file
@ -0,0 +1,8 @@
|
||||
// SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
//
|
||||
// SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
|
||||
import App from "./App.vue";
|
||||
import {createVueApp} from "@res/js/vue";
|
||||
|
||||
const app = createVueApp(App).mount('#vueapp')
|
@ -1,86 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
$('a.groupheadline').on('click',function(){
|
||||
if(parseInt($(this).data('id')) > 0) {
|
||||
$('#GroupheadlineDialogGroupId').val($(this).data('id'));
|
||||
$('#GroupheadlineDialogArticleId').val($(this).data('article'));
|
||||
$('#GroupheadlineDialogGroupName').val($(this).data('name'));
|
||||
$('#GroupheadlineDialog').dialog('open');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$('#GroupheadlineDialog').dialog(
|
||||
{
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
minWidth: 940,
|
||||
title:'',
|
||||
buttons: {
|
||||
'ABBRECHEN': function() {
|
||||
$(this).dialog('close');
|
||||
},
|
||||
'ÄNDERN': function()
|
||||
{
|
||||
if($('#GroupheadlineDialogGroupName').val()+'' !== '') {
|
||||
$.ajax({
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=changegroupname',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
groupId: $('#GroupheadlineDialogGroupId').val(),
|
||||
groupName: $('#GroupheadlineDialogGroupName').val()
|
||||
},
|
||||
success: function (data) {
|
||||
if(typeof data.status != 'undefined' && data.status == 1) {
|
||||
window.location.href = window.location.href.split('#')[0];
|
||||
}
|
||||
},
|
||||
beforeSend: function () {
|
||||
|
||||
}
|
||||
});
|
||||
}else{
|
||||
alert('Bitte eine Bezeichnung angeben');
|
||||
}
|
||||
},
|
||||
'LÖSCHEN': function() {
|
||||
$.ajax({
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=deletegroup',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
groupId: $('#GroupheadlineDialogGroupId').val()
|
||||
},
|
||||
success: function(data) {
|
||||
if(typeof data.status != 'undefined' && data.status == 1) {
|
||||
if (typeof data.confirm != 'undefined' && data.confirm == 1) {
|
||||
if(confirm('Die Gruppe enthält Option, sollen die Gruppe mit diesen Optionen wirklich gelöscht werden?'))
|
||||
{
|
||||
$.ajax({
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=deletegroup',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
force:1,groupId: $('#GroupheadlineDialogGroupId').val()
|
||||
},success: function(data) {
|
||||
window.location.href = window.location.href.split('#')[0];
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
window.location.href = window.location.href.split('#')[0];
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeSend: function() {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
close: function(event, ui){
|
||||
|
||||
}
|
||||
});
|
@ -1,513 +0,0 @@
|
||||
var MatrixproductListview = function ($) {
|
||||
"use strict";
|
||||
|
||||
var me = {
|
||||
storage:{
|
||||
selectedArticles: '',
|
||||
optionTableloaded: false,
|
||||
groupTableloaded: false,
|
||||
articleTableloaded: false,
|
||||
},
|
||||
selector: {
|
||||
divlistview: 'div.listview',
|
||||
popupGroup: '#popupgroup',
|
||||
popupOption: '#popupoption',
|
||||
popupArticleCreate: '#popuparcticlecreate',
|
||||
popupArticle: '#popuparticle',
|
||||
btnNewGroup: '#newGroup',
|
||||
btnNewOption: '#newOption',
|
||||
articleTable: '#matrixprodukt_list_view',
|
||||
groupTable: '#matrixprodukt_list_view_group',
|
||||
optionTable: '#matrixprodukt_list_view_options',
|
||||
},
|
||||
editArticle: function(id) {
|
||||
if(id > 0) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=listgetarticle',
|
||||
data: {
|
||||
articleid: $(me.selector.popupGroup).data('articleid'),
|
||||
listid: id
|
||||
},
|
||||
success: function (data) {
|
||||
$('div#options').html(data.optionhtml);
|
||||
$('#articlelistid').val(data.id);
|
||||
$(me.selector.popupArticle).dialog('open');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
editGroup: function(id){
|
||||
$('#groupid').val(id);
|
||||
if(id > 0) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=listgetgroup',
|
||||
data: {
|
||||
articleid: $(me.selector.popupGroup).data('articleid'),
|
||||
groupid: $('#groupid').val()
|
||||
},
|
||||
success: function (data) {
|
||||
$('#groupname').val(data.name);
|
||||
$(me.selector.popupGroup).dialog('open');
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
$(me.selector.popupGroup).dialog('open');
|
||||
},
|
||||
deleteGroup: function(id) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=listdeletegroupcheck',
|
||||
data: {
|
||||
articleid: $(me.selector.popupGroup).data('articleid'),
|
||||
groupid: id
|
||||
},
|
||||
success: function (data) {
|
||||
if(typeof data.message) {
|
||||
if(!confirm(data.message)) {
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=listdeletegroup',
|
||||
data: {
|
||||
articleid: $(me.selector.popupGroup).data('articleid'),
|
||||
groupid: data.groupid
|
||||
},
|
||||
success: function (data) {
|
||||
if(typeof data.url !== 'undefined') {
|
||||
window.location.href=data.url;
|
||||
return;
|
||||
}
|
||||
$(me.selector.optionTable).DataTable().ajax.reload();
|
||||
$(me.selector.groupTable).DataTable().ajax.reload();
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
$(me.selector.optionTable).DataTable().ajax.reload();
|
||||
$(me.selector.groupTable).DataTable().ajax.reload();
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
deleteOption: function(id) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=listdeleteoptioncheck',
|
||||
data: {
|
||||
articleid: $(me.selector.popupGroup).data('articleid'),
|
||||
optionid: id
|
||||
},
|
||||
success: function (data) {
|
||||
if(typeof data.message) {
|
||||
if(!confirm(data.message)) {
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=listdeleteoption',
|
||||
data: {
|
||||
articleid: $(me.selector.popupGroup).data('articleid'),
|
||||
optionid: data.optionid
|
||||
},
|
||||
success: function () {
|
||||
$(me.selector.optionTable).DataTable().ajax.reload();
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
},
|
||||
error: function() {
|
||||
$(me.selector.optionTable).DataTable().ajax.reload();
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
generateList: function()
|
||||
{
|
||||
$('#tabs-1').loadingOverlay('show');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=generatelist',
|
||||
data: {
|
||||
articleid: $(me.selector.popupGroup).data('articleid')
|
||||
},
|
||||
success: function (data) {
|
||||
if(typeof data.url != 'undefined') {
|
||||
window.location.href=data.url;
|
||||
return;
|
||||
}
|
||||
$('#tabs-1').loadingOverlay('remove');
|
||||
},
|
||||
error:function()
|
||||
{
|
||||
$('#tabs-1').loadingOverlay('remove');
|
||||
}
|
||||
});
|
||||
},
|
||||
massedit: function(){
|
||||
me.storage.selectedArticles= '';
|
||||
$(me.selector.articleTable).find('input:checked').each(function(){
|
||||
if($(this).data('articleid') > 0) {
|
||||
if (me.storage.selectedArticles !== '') {
|
||||
me.storage.selectedArticles
|
||||
= me.storage.selectedArticles + ';';
|
||||
}
|
||||
me.storage.selectedArticles
|
||||
= me.storage.selectedArticles
|
||||
+ $(this).data('articleid')
|
||||
}
|
||||
|
||||
});
|
||||
if(me.storage.selectedArticles !== '') {
|
||||
matrixproduktedit_open(me.storage.selectedArticles);
|
||||
}
|
||||
else {
|
||||
alert('Kein Artikel ausgwählt');
|
||||
}
|
||||
},
|
||||
createallmissingarticles: function() {
|
||||
me.storage.selectedArticles= 'ALL';
|
||||
$('#listids').val(me.storage.selectedArticles);
|
||||
$(me.selector.popupArticleCreate).dialog('open');
|
||||
},
|
||||
createMissingArticles: function(){
|
||||
me.storage.selectedArticles= '';
|
||||
$(me.selector.articleTable).find('input:checked').each(function(){
|
||||
if(me.storage.selectedArticles !== '') {
|
||||
me.storage.selectedArticles
|
||||
=me.storage.selectedArticles + ';';
|
||||
}
|
||||
me.storage.selectedArticles
|
||||
=me.storage.selectedArticles
|
||||
+$(this).data('id')
|
||||
});
|
||||
if(me.storage.selectedArticles !== '') {
|
||||
$('#listids').val(me.storage.selectedArticles);
|
||||
$(me.selector.popupArticleCreate).dialog('open');
|
||||
}
|
||||
},
|
||||
editOption: function(id){
|
||||
$('#optionid').val(id);
|
||||
if(id > 0) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=listgetoption',
|
||||
data: {
|
||||
articleid: $(me.selector.popupGroup).data('articleid'),
|
||||
optionid: $('#optionid').val()
|
||||
},
|
||||
success: function (data) {
|
||||
$('#optionname').val(data.name);
|
||||
$('#optiongroup').html(data.groups);
|
||||
$('#optiongroup').val(data.gruppe);
|
||||
$(me.selector.popupOption).dialog('open');
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
else {
|
||||
$('#optionname').val('');
|
||||
}
|
||||
|
||||
$(me.selector.popupOption).dialog('open');
|
||||
|
||||
},
|
||||
|
||||
articeTableAfterReload:function(){
|
||||
$(me.selector.articleTable).find('img.editarticle').on('click',function(){
|
||||
me.editArticle($(this).data('id'));
|
||||
});
|
||||
me.storage.articleTableloaded = true;
|
||||
},
|
||||
groupTableAfterReload:function(){
|
||||
$(me.selector.groupTable).find('img.editgroup').on('click',function(){
|
||||
me.editGroup($(this).data('id'));
|
||||
});
|
||||
$(me.selector.groupTable).find('img.deletegroup').on('click',function(){
|
||||
me.deleteGroup($(this).data('id'));
|
||||
});
|
||||
me.storage.groupTableloaded = true;
|
||||
},
|
||||
optionTableAfterReload:function(){
|
||||
$(me.selector.optionTable).find('img.editoption').on('click',function(){
|
||||
me.editOption($(this).data('id'));
|
||||
});
|
||||
$(me.selector.optionTable).find('img.deleteoption').on('click',function(){
|
||||
me.deleteOption($(this).data('id'));
|
||||
});
|
||||
me.storage.optionTableloaded = true;
|
||||
},
|
||||
createMissingAriclesSave: function()
|
||||
{
|
||||
$(me.selector.popupArticleCreate).parent().loadingOverlay('show');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=createarticles',
|
||||
data: {
|
||||
listids:$('#listids').val(),
|
||||
articleid: $(me.selector.popupGroup).data('articleid'),
|
||||
fromcategory: $('#fromcategory').prop('checked')?1:0,
|
||||
fromoption: $('#fromoption').prop('checked')?1:0,
|
||||
fromsuffix: $('#fromsuffix').prop('checked')?1:0,
|
||||
fromprefix: $('#fromprefix').prop('checked')?1:0,
|
||||
prefixseparator: $('#prefixseparator').val(),
|
||||
prefixcount: $('#prefixcount').val(),
|
||||
prefixnextnumber: $('#prefixnextnumber').val(),
|
||||
appendname: $('#prefixseparator').prop('checked')?1:0,
|
||||
nextprefixnumber: $('#nextprefixnumber').val(),
|
||||
},
|
||||
success: function (data) {
|
||||
$(me.selector.popupArticleCreate).parent().loadingOverlay('remove');
|
||||
|
||||
if(typeof data.continue != 'undefined' && data.continue == 1) {
|
||||
if(typeof data.nextprefixnumber != 'undefined') {
|
||||
$('#nextprefixnumber').val(data.nextprefixnumber);
|
||||
}
|
||||
me.createMissingAriclesSave();
|
||||
return;
|
||||
}
|
||||
$('#nextprefixnumber').val('');
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
$(me.selector.popupArticleCreate).dialog('close');
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
$(me.selector.popupArticleCreate).parent().loadingOverlay('remove');
|
||||
$('#nextprefixnumber').val('');
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
$(me.selector.popupArticleCreate).dialog('close');
|
||||
}
|
||||
});
|
||||
},
|
||||
initListView: function(){
|
||||
$(me.selector.popupGroup).dialog(
|
||||
{
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
minWidth: 940,
|
||||
title: '',
|
||||
buttons: {
|
||||
'ABBRECHEN':function(){
|
||||
$(me.selector.popupGroup).dialog('close');
|
||||
},
|
||||
'SPEICHERN': function () {
|
||||
$(me.selector.popupGroup).parent().loadingOverlay('show');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=listsavegroup',
|
||||
data: {
|
||||
articleid: $(me.selector.popupGroup).data('articleid'),
|
||||
name: $('#groupname').val(),
|
||||
groupid: $('#groupid').val()
|
||||
},
|
||||
success: function (data) {
|
||||
if(typeof data.url != 'undefined') {
|
||||
window.location.href=data.url;
|
||||
return;
|
||||
}
|
||||
$(me.selector.groupTable).DataTable().ajax.reload();
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
$(me.selector.popupGroup).parent().loadingOverlay('remove');
|
||||
},
|
||||
error: function()
|
||||
{
|
||||
$(me.selector.groupTable).DataTable().ajax.reload();
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
$(me.selector.popupGroup).parent().loadingOverlay('remove');
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
$(me.selector.popupArticleCreate).dialog(
|
||||
{
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
minWidth: 940,
|
||||
title: '',
|
||||
buttons: {
|
||||
'ABBRECHEN':function(){
|
||||
$(me.selector.popupArticleCreate).dialog('close');
|
||||
},
|
||||
'SPEICHERN': function () {
|
||||
me.createMissingAriclesSave();
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
$(me.selector.popupArticle).dialog(
|
||||
{
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
minWidth: 940,
|
||||
title: '',
|
||||
buttons: {
|
||||
'ABBRECHEN':function(){
|
||||
$(me.selector.popupArticle).dialog('close');
|
||||
},
|
||||
'SPEICHERN': function () {
|
||||
$(me.selector.popupArticle).parent().loadingOverlay('show');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=listsavearticle',
|
||||
data: {
|
||||
articleid: $(me.selector.popupGroup).data('articleid'),
|
||||
listid:$('#articlelistid').val(),
|
||||
option1: (typeof $('#option1').val() != 'undefined'?$('#option1').val():0),
|
||||
option2: (typeof $('#option2').val() != 'undefined'?$('#option2').val():0),
|
||||
option3: (typeof $('#option3').val() != 'undefined'?$('#option3').val():0),
|
||||
option4: (typeof $('#option4').val() != 'undefined'?$('#option4').val():0),
|
||||
option5: (typeof $('#option5').val() != 'undefined'?$('#option5').val():0),
|
||||
option6: (typeof $('#option6').val() != 'undefined'?$('#option6').val():0),
|
||||
option7: (typeof $('#option7').val() != 'undefined'?$('#option7').val():0),
|
||||
option8: (typeof $('#option8').val() != 'undefined'?$('#option8').val():0),
|
||||
option9: (typeof $('#option9').val() != 'undefined'?$('#option9').val():0),
|
||||
option10: (typeof $('#option10').val() != 'undefined'?$('#option10').val():0),
|
||||
option11: (typeof $('#option11').val() != 'undefined'?$('#option11').val():0),
|
||||
option12: (typeof $('#option12').val() != 'undefined'?$('#option12').val():0),
|
||||
option13: (typeof $('#option13').val() != 'undefined'?$('#option13').val():0),
|
||||
option14: (typeof $('#option14').val() != 'undefined'?$('#option14').val():0),
|
||||
option15: (typeof $('#option15').val() != 'undefined'?$('#option15').val():0),
|
||||
option16: (typeof $('#option16').val() != 'undefined'?$('#option16').val():0),
|
||||
option17: (typeof $('#option17').val() != 'undefined'?$('#option17').val():0),
|
||||
option18: (typeof $('#option18').val() != 'undefined'?$('#option18').val():0),
|
||||
option19: (typeof $('#option19').val() != 'undefined'?$('#option19').val():0),
|
||||
option20: (typeof $('#option20').val() != 'undefined'?$('#option20').val():0),
|
||||
},
|
||||
success: function () {
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
$(me.selector.popupArticle).parent().loadingOverlay('remove');
|
||||
$(me.selector.popupArticle).dialog('close');
|
||||
},
|
||||
error: function() {
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
$(me.selector.popupArticle).parent().loadingOverlay('remove');
|
||||
$(me.selector.popupArticle).dialog('close');
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
$(me.selector.popupOption).dialog(
|
||||
{
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
minWidth: 940,
|
||||
title: '',
|
||||
buttons: {
|
||||
'ABBRECHEN':function(){
|
||||
$(me.selector.popupOption).dialog('close');
|
||||
},
|
||||
'SPEICHERN': function () {
|
||||
$(me.selector.popupOption).parent().loadingOverlay('show');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
url: 'index.php?module=matrixprodukt&action=artikel&cmd=listsaveoption',
|
||||
data: {
|
||||
articleid: $(me.selector.popupGroup).data('articleid'),
|
||||
name: $('#optionname').val(),
|
||||
groupid: $('#optiongroup').val(),
|
||||
optionid: $('#optionid').val()
|
||||
},
|
||||
success: function () {
|
||||
$(me.selector.optionTable).DataTable().ajax.reload();
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
$(me.selector.popupOption).parent().loadingOverlay('remove');
|
||||
$(me.selector.popupOption).dialog('close');
|
||||
},
|
||||
error: function(){
|
||||
$(me.selector.optionTable).DataTable().ajax.reload();
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
$(me.selector.popupOption).parent().loadingOverlay('remove');
|
||||
$(me.selector.popupOption).dialog('close');
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
$(me.selector.popupGroup).toggleClass('hidden', false);
|
||||
$(me.selector.popupOption).toggleClass('hidden', false);
|
||||
$(me.selector.popupArticle).toggleClass('hidden', false);
|
||||
$(me.selector.popupArticleCreate).toggleClass('hidden', false);
|
||||
|
||||
$(me.selector.articleTable).on('afterreload', function(){
|
||||
me.articeTableAfterReload();
|
||||
});
|
||||
$(me.selector.optionTable).on('afterreload', function(){
|
||||
me.optionTableAfterReload();
|
||||
});
|
||||
$(me.selector.groupTable).on('afterreload', function(){
|
||||
me.groupTableAfterReload();
|
||||
});
|
||||
$(me.selector.btnNewGroup).on('click',function(){
|
||||
me.editGroup(0);
|
||||
});
|
||||
$(me.selector.btnNewOption).on('click',function(){
|
||||
me.editOption(0);
|
||||
});
|
||||
$('#changeall').on('change',function(){
|
||||
$(me.selector.articleTable).find('input.select').prop('checked', $('#changeall').prop('checked'));
|
||||
});
|
||||
$('#createmissingarticles').on('click',function () {
|
||||
me.createMissingArticles();
|
||||
});
|
||||
$('#createallmissingarticles').on('click',function () {
|
||||
me.createallmissingarticles();
|
||||
});
|
||||
$('#massedit').on('click',function () {
|
||||
me.massedit();
|
||||
});
|
||||
$('#generatelist').on('click',function () {
|
||||
me.generateList();
|
||||
});
|
||||
if(!me.storage.optionTableloaded) {
|
||||
$(me.selector.optionTable).DataTable().ajax.reload();
|
||||
}
|
||||
if(!me.storage.groupTableloaded) {
|
||||
$(me.selector.groupTable).DataTable().ajax.reload();
|
||||
}
|
||||
if(!me.storage.articleTableloaded) {
|
||||
$(me.selector.articleTable).DataTable().ajax.reload();
|
||||
}
|
||||
},
|
||||
init: function () {
|
||||
if($(me.selector.divlistview).length) {
|
||||
me.initListView();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
init: me.init,
|
||||
}
|
||||
|
||||
}(jQuery);
|
||||
|
||||
$(document).ready(function () {
|
||||
MatrixproductListview.init();
|
||||
});
|
27296
package-lock.json
generated
27296
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@ -11,15 +11,19 @@
|
||||
"production": "./node_modules/cross-env/src/bin/cross-env-shell.js NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"raml2html": "^7.6.0",
|
||||
"raml2html-werk-theme": "^1.1.0",
|
||||
"cross-env": "^7.0",
|
||||
"laravel-mix": "^5.0.1",
|
||||
"raml2html": "^7.6.0",
|
||||
"raml2html-werk-theme": "^1.1.0",
|
||||
"resolve-url-loader": "^3.1.0",
|
||||
"sass": "^1.15.2",
|
||||
"sass-loader": "^8.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^2.6.12"
|
||||
"@vitejs/plugin-vue": "^4.3.4",
|
||||
"axios": "^1.5.0",
|
||||
"primevue": "^3.35.0",
|
||||
"vite": "^4.4.9",
|
||||
"vue": "^3.3.4"
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,12 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Xentral ERP Software GmbH, Fuggerstrasse 11, D-86150 Augsburg
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
*/
|
||||
|
||||
/*
|
||||
**** COPYRIGHT & LICENSE NOTICE *** DO NOT REMOVE ****
|
||||
*
|
||||
@ -317,9 +325,11 @@ class Player {
|
||||
|
||||
$moduleClassName = strtoupper($module[0]) . substr($module, 1);
|
||||
$this->app->ModuleScriptCache->IncludeModule($moduleClassName);
|
||||
$this->app->ModuleScriptCache->IncludeJavascriptModules('_theme_', ['www/themes/new/js/main.js']);
|
||||
$this->app->Tpl->Add('MODULESTYLESHEET', $this->app->ModuleScriptCache->GetStylesheetHtmlTags());
|
||||
$this->app->Tpl->Add('MODULEJAVASCRIPTHEAD', $this->app->ModuleScriptCache->GetJavascriptHtmlTags('head'));
|
||||
$this->app->Tpl->Add('MODULEJAVASCRIPTBODY', $this->app->ModuleScriptCache->GetJavascriptHtmlTags('body'));
|
||||
$this->app->Tpl->Set('JAVASCRIPTMODULES', $this->app->ModuleScriptCache->GetJavascriptModulesHtmlTags());
|
||||
|
||||
$permission = true;
|
||||
if(isset($myApp) && method_exists($myApp,'CheckRights'))$permission = $myApp->CheckRights();
|
||||
@ -412,7 +422,7 @@ class Player {
|
||||
else{
|
||||
|
||||
$this->app->Tpl->Set('VUEJS', 'vue.min.js');
|
||||
$this->app->erp->RunHook('before_final_parse_page');
|
||||
$this->app->erp->RunHook('before_final_parse_page');
|
||||
echo $this->app->Tpl->FinalParse('page.tpl');
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,12 @@
|
||||
<?php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Xentral ERP Software GmbH, Fuggerstrasse 11, D-86150 Augsburg
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
*/
|
||||
|
||||
/*
|
||||
**** COPYRIGHT & LICENSE NOTICE *** DO NOT REMOVE ****
|
||||
*
|
||||
@ -10,8 +18,8 @@
|
||||
* to obtain the text of the corresponding license version.
|
||||
*
|
||||
**** END OF COPYRIGHT & LICENSE NOTICE *** DO NOT REMOVE ****
|
||||
*/
|
||||
?>
|
||||
*/
|
||||
?>
|
||||
<?php
|
||||
|
||||
/**
|
||||
@ -34,12 +42,19 @@ class ModuleScriptCache
|
||||
/** @var string $relativeCacheDir Relativer Pfad zum Cache-Ordner (ausgehend von www) */
|
||||
protected $relativeCacheDir;
|
||||
|
||||
protected $assetDir;
|
||||
|
||||
/** @var object $assetManifest Parsed manifest.json from vite */
|
||||
protected $assetManifest;
|
||||
|
||||
/** @var array $javascriptFiles Absolute Pfade zu Javascript-Dateien die gecached werden sollen */
|
||||
protected $javascriptFiles = [
|
||||
'head' => [],
|
||||
'body' => [],
|
||||
];
|
||||
|
||||
protected $javascriptModules = [];
|
||||
|
||||
/** @var array $stylesheetFiles Absolute Pfade zu Stylesheet-Dateien die gecached werden sollen */
|
||||
protected $stylesheetFiles = [];
|
||||
|
||||
@ -48,6 +63,8 @@ class ModuleScriptCache
|
||||
$this->baseDir = dirname(dirname(__DIR__));
|
||||
$this->absoluteCacheDir = $this->baseDir . '/www/cache';
|
||||
$this->relativeCacheDir = './cache';
|
||||
$this->assetDir = '/dist';
|
||||
$this->assetManifest = json_decode(file_get_contents($this->baseDir. '/www' . $this->assetDir . '/manifest.json'));
|
||||
|
||||
// Cache-Ordner anzulegen, falls nicht existent
|
||||
if (!is_dir($this->absoluteCacheDir)) {
|
||||
@ -74,6 +91,7 @@ class ModuleScriptCache
|
||||
// Javascript- und Stylesheet-Dateien sind als Eigenschaft im Modul definiert
|
||||
$javascript = $this->GetClassProperty($legacyModuleClassName, 'javascript');
|
||||
$stylesheet = $this->GetClassProperty($legacyModuleClassName, 'stylesheet');
|
||||
$jsmodules = $this->GetClassProperty($legacyModuleClassName, 'jsmodules');
|
||||
|
||||
// Falls nicht im Modul definiert > Defaults verwenden
|
||||
if (empty($javascript)) {
|
||||
@ -82,9 +100,13 @@ class ModuleScriptCache
|
||||
if (empty($stylesheet)) {
|
||||
$stylesheet = [$this->GetDefaultModuleStylesheetFile($newModuleName)];
|
||||
}
|
||||
if (empty($jsmodules)) {
|
||||
$jsmodules = $this->GetDefaultModuleJavascriptModules($newModuleName);
|
||||
}
|
||||
|
||||
$this->IncludeJavascriptFiles($newModuleName, $javascript);
|
||||
$this->IncludeStylesheetFiles($newModuleName, $stylesheet);
|
||||
$this->IncludeJavascriptModules($newModuleName, $jsmodules);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -193,6 +215,20 @@ class ModuleScriptCache
|
||||
}
|
||||
}
|
||||
|
||||
public function IncludeJavascriptModules(string $moduleName, array $files) : void
|
||||
{
|
||||
foreach ($files as $file) {
|
||||
$realPath = realpath($this->baseDir . '/' . $file);
|
||||
if (!is_file($realPath))
|
||||
continue;
|
||||
|
||||
if (isset($this->assetManifest->$file))
|
||||
$this->javascriptModules[] = $this->assetManifest->$file;
|
||||
else
|
||||
$this->javascriptModules[] = $realPath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cacheName Name unter dem die Cache-Datei zusammengefasst werden
|
||||
* @param array $files Array mit relativen Pfaden zur Xentral-Installation
|
||||
@ -258,6 +294,36 @@ class ModuleScriptCache
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function GetJavascriptModulesHtmlTags() : string
|
||||
{
|
||||
if (empty($this->javascriptModules))
|
||||
return '';
|
||||
|
||||
$html = '';
|
||||
foreach ($this->javascriptModules as $module) {
|
||||
if (is_object($module)) {
|
||||
if (defined('VITE_DEV_SERVER')) {
|
||||
$url = VITE_DEV_SERVER . $module->src;
|
||||
} else {
|
||||
$url = $this->assetDir . '/' . $module->file;
|
||||
if (isset($module->css)) {
|
||||
foreach ($module->css as $css)
|
||||
$html .= sprintf('<link rel="stylesheet" type="text/css" href="%s" />', $this->assetDir.'/'.$css);
|
||||
$html .= "\r\n";
|
||||
}
|
||||
}
|
||||
} elseif (str_starts_with($module,$this->baseDir.'/www')) {
|
||||
$url = substr($module, strlen($this->baseDir)+4);
|
||||
}
|
||||
|
||||
if (isset($url)) {
|
||||
$html .= sprintf('<script type="module" src="%s"></script>', $url);
|
||||
$html .= "\r\n";
|
||||
}
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@ -389,6 +455,18 @@ class ModuleScriptCache
|
||||
return sprintf('./classes/Modules/%s/www/js/%s.js', $moduleName, strtolower($moduleName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $moduleName
|
||||
* @return string relative path to default Javascript-Module-File
|
||||
*/
|
||||
protected function GetDefaultModuleJavascriptModules(string $moduleName): array
|
||||
{
|
||||
return [
|
||||
sprintf('classes/Modules/%s/www/js/entry.js', $moduleName),
|
||||
sprintf('classes/Modules/%s/www/js/entry.jsx', $moduleName)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $moduleName
|
||||
*
|
||||
|
29
resources/css/primevue/_base.css
Normal file
29
resources/css/primevue/_base.css
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@import "autocomplete.css";
|
||||
@import "dialog.css";
|
||||
@import "dropdown.css";
|
||||
@import "listbox.css";
|
||||
|
||||
.p-component-overlay {
|
||||
background-color: rgba(170,170,170,0.7);
|
||||
}
|
||||
|
||||
.p-button {
|
||||
background-color: var(--button-primary-background);
|
||||
padding: 6px;
|
||||
margin: 3px;
|
||||
color: white;
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--button-primary-border-color);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.p-icon {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
94
resources/css/primevue/autocomplete.css
Normal file
94
resources/css/primevue/autocomplete.css
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
.p-autocomplete .p-autocomplete-loader {
|
||||
right: 0.75rem;
|
||||
}
|
||||
.p-autocomplete.p-autocomplete-dd .p-autocomplete-loader {
|
||||
right: 3.107rem;
|
||||
}
|
||||
.p-autocomplete:not(.p-disabled):hover .p-autocomplete-multiple-container {
|
||||
border-color: #ced4da;
|
||||
}
|
||||
.p-autocomplete:not(.p-disabled).p-focus .p-autocomplete-multiple-container {
|
||||
outline: 0 none;
|
||||
outline-offset: 0;
|
||||
box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5);
|
||||
border-color: #007bff;
|
||||
}
|
||||
.p-autocomplete .p-autocomplete-multiple-container {
|
||||
padding: 0.25rem 0.75rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.p-autocomplete .p-autocomplete-multiple-container .p-autocomplete-input-token {
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
.p-autocomplete .p-autocomplete-multiple-container .p-autocomplete-input-token input {
|
||||
font-family: inherit;
|
||||
font-feature-settings: inherit;
|
||||
font-size: inherit;
|
||||
color: #212529;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.p-autocomplete .p-autocomplete-multiple-container .p-autocomplete-token {
|
||||
padding: 0.25rem 0.75rem;
|
||||
background: #dee2e6;
|
||||
color: #212529;
|
||||
border-radius: 16px;
|
||||
}
|
||||
.p-autocomplete .p-autocomplete-multiple-container .p-autocomplete-token .p-autocomplete-token-icon {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
.p-autocomplete .p-autocomplete-multiple-container .p-autocomplete-token.p-focus {
|
||||
background: #ced4da;
|
||||
color: #212529;
|
||||
}
|
||||
.p-autocomplete.p-invalid.p-component > .p-inputtext {
|
||||
border-color: #dc3545;
|
||||
}
|
||||
|
||||
.p-autocomplete-panel {
|
||||
background: #ffffff;
|
||||
color: var(--grey);
|
||||
border: 1px solid var(--fieldset-dark);
|
||||
border-radius: 4px;
|
||||
box-shadow: none;
|
||||
}
|
||||
.p-autocomplete-panel .p-autocomplete-items {
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
.p-autocomplete-panel .p-autocomplete-items .p-autocomplete-item {
|
||||
margin: 0;
|
||||
padding: 3px;
|
||||
border: 0 none;
|
||||
color: #212529;
|
||||
background: transparent;
|
||||
transition: box-shadow 0.15s;
|
||||
border-radius: 0;
|
||||
}
|
||||
.p-autocomplete-panel .p-autocomplete-items .p-autocomplete-item.p-highlight {
|
||||
color: #ffffff;
|
||||
background: #007bff;
|
||||
}
|
||||
.p-autocomplete-panel .p-autocomplete-items .p-autocomplete-item.p-highlight.p-focus {
|
||||
background: #0067d6;
|
||||
}
|
||||
.p-autocomplete-panel .p-autocomplete-items .p-autocomplete-item:not(.p-highlight):not(.p-disabled).p-focus {
|
||||
color: #212529;
|
||||
background: #dee2e6;
|
||||
}
|
||||
.p-autocomplete-panel .p-autocomplete-items .p-autocomplete-item:not(.p-highlight):not(.p-disabled):hover {
|
||||
color: #212529;
|
||||
background: #e9ecef;
|
||||
}
|
||||
.p-autocomplete-panel .p-autocomplete-items .p-autocomplete-item-group {
|
||||
margin: 0;
|
||||
padding: 0.75rem 1rem;
|
||||
color: #212529;
|
||||
background: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
34
resources/css/primevue/dialog.css
Normal file
34
resources/css/primevue/dialog.css
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
.p-dialog {
|
||||
background-color: var(--body-background);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.p-dialog-header {
|
||||
color: #6d6d6f;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
padding: .4em 1em;
|
||||
}
|
||||
|
||||
.p-dialog .p-dialog-header .p-dialog-header-icon {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.p-dialog .p-dialog-content {
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
|
||||
.p-dialog .p-dialog-footer {
|
||||
border-top: 1px solid var(--fieldset-dark);
|
||||
padding: 0.3em 1em 0.5em 0.4em;
|
||||
text-align: right;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
129
resources/css/primevue/dropdown.css
Normal file
129
resources/css/primevue/dropdown.css
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
.p-dropdown {
|
||||
background: #ffffff;
|
||||
border: 1px solid #ced4da;
|
||||
transition: background-color 0.15s, border-color 0.15s, box-shadow 0.15s;
|
||||
border-radius: 4px;
|
||||
padding: 4px 5px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.p-dropdown:not(.p-disabled):hover {
|
||||
border-color: #ced4da;
|
||||
}
|
||||
.p-dropdown:not(.p-disabled).p-focus {
|
||||
outline: 0 none;
|
||||
outline-offset: 0;
|
||||
box-shadow: 0 0 0 0.2rem rgba(38, 143, 255, 0.5);
|
||||
border-color: #007bff;
|
||||
}
|
||||
.p-dropdown.p-dropdown-clearable .p-dropdown-label {
|
||||
padding-right: 1.75rem;
|
||||
}
|
||||
.p-dropdown .p-dropdown-label {
|
||||
background: transparent;
|
||||
border: 0 none;
|
||||
color: #6d6d6f;
|
||||
}
|
||||
.p-dropdown .p-dropdown-label.p-placeholder {
|
||||
color: #6c757d;
|
||||
}
|
||||
.p-dropdown .p-dropdown-label:focus, .p-dropdown .p-dropdown-label:enabled:focus {
|
||||
outline: 0 none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.p-dropdown .p-dropdown-trigger {
|
||||
background: transparent;
|
||||
color: #495057;
|
||||
width: 2.357rem;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
.p-dropdown .p-dropdown-clear-icon {
|
||||
color: #495057;
|
||||
right: 2.357rem;
|
||||
}
|
||||
.p-dropdown.p-invalid.p-component {
|
||||
border-color: #dc3545;
|
||||
}
|
||||
|
||||
.p-dropdown-panel {
|
||||
background: #ffffff;
|
||||
color: var(--grey);
|
||||
border: 1px solid var(--fieldset-dark);
|
||||
border-radius: 4px;
|
||||
box-shadow: none;
|
||||
}
|
||||
.p-dropdown-panel .p-dropdown-header {
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
color: #212529;
|
||||
background: #efefef;
|
||||
margin: 0;
|
||||
border-top-right-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
.p-dropdown-panel .p-dropdown-header .p-dropdown-filter {
|
||||
padding-right: 1.75rem;
|
||||
margin-right: -1.75rem;
|
||||
}
|
||||
.p-dropdown-panel .p-dropdown-header .p-dropdown-filter-icon {
|
||||
right: 0.75rem;
|
||||
color: #495057;
|
||||
}
|
||||
.p-dropdown-panel .p-dropdown-items {
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
.p-dropdown-panel .p-dropdown-items .p-dropdown-item {
|
||||
margin: 0;
|
||||
padding: 3px;
|
||||
border: 0 none;
|
||||
color: #212529;
|
||||
background: transparent;
|
||||
transition: box-shadow 0.15s;
|
||||
border-radius: 0;
|
||||
}
|
||||
.p-dropdown-panel .p-dropdown-items .p-dropdown-item.p-highlight {
|
||||
color: #ffffff;
|
||||
background: #007bff;
|
||||
}
|
||||
.p-dropdown-panel .p-dropdown-items .p-dropdown-item.p-highlight.p-focus {
|
||||
background: #0067d6;
|
||||
}
|
||||
.p-dropdown-panel .p-dropdown-items .p-dropdown-item:not(.p-highlight):not(.p-disabled).p-focus {
|
||||
color: #212529;
|
||||
background: #dee2e6;
|
||||
}
|
||||
.p-dropdown-panel .p-dropdown-items .p-dropdown-item:not(.p-highlight):not(.p-disabled):hover {
|
||||
color: #212529;
|
||||
background: #e9ecef;
|
||||
}
|
||||
.p-dropdown-panel .p-dropdown-items .p-dropdown-item-group {
|
||||
margin: 0;
|
||||
padding: 0.75rem 1rem;
|
||||
color: #212529;
|
||||
background: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
.p-dropdown-panel .p-dropdown-items .p-dropdown-empty-message {
|
||||
padding: 0.5rem 1.5rem;
|
||||
color: #212529;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.p-input-filled .p-dropdown {
|
||||
background: #efefef;
|
||||
}
|
||||
.p-input-filled .p-dropdown:not(.p-disabled):hover {
|
||||
background-color: #efefef;
|
||||
}
|
||||
.p-input-filled .p-dropdown:not(.p-disabled).p-focus {
|
||||
background-color: #efefef;
|
||||
}
|
||||
.p-input-filled .p-dropdown:not(.p-disabled).p-focus .p-inputtext {
|
||||
background-color: transparent;
|
||||
}
|
75
resources/css/primevue/listbox.css
Normal file
75
resources/css/primevue/listbox.css
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
.p-listbox {
|
||||
background: #ffffff;
|
||||
color: #6d6d6f;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.15s, border-color 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
.p-listbox .p-listbox-header {
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
color: #212529;
|
||||
background: #efefef;
|
||||
margin: 0;
|
||||
border-top-right-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
.p-listbox .p-listbox-header .p-listbox-filter {
|
||||
padding-right: 1.75rem;
|
||||
}
|
||||
.p-listbox .p-listbox-header .p-listbox-filter-icon {
|
||||
right: 0.75rem;
|
||||
color: #495057;
|
||||
}
|
||||
.p-listbox .p-listbox-list {
|
||||
padding: 0.5rem 0;
|
||||
outline: 0 none;
|
||||
}
|
||||
.p-listbox .p-listbox-list .p-listbox-item {
|
||||
margin: 0;
|
||||
padding: 0.5rem 1.5rem;
|
||||
border: 0 none;
|
||||
color: #212529;
|
||||
transition: box-shadow 0.15s;
|
||||
border-radius: 0;
|
||||
}
|
||||
.p-listbox .p-listbox-list .p-listbox-item.p-highlight {
|
||||
color: #ffffff;
|
||||
background: var(--green);
|
||||
}
|
||||
.p-listbox .p-listbox-list .p-listbox-item-group {
|
||||
margin: 0;
|
||||
padding: 0.75rem 1rem;
|
||||
color: #212529;
|
||||
background: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
.p-listbox .p-listbox-list .p-listbox-empty-message {
|
||||
padding: 0.5rem 1.5rem;
|
||||
color: #212529;
|
||||
background: transparent;
|
||||
}
|
||||
.p-listbox:not(.p-disabled) .p-listbox-item.p-highlight.p-focus {
|
||||
background: var(--green);
|
||||
}
|
||||
.p-listbox:not(.p-disabled) .p-listbox-item:not(.p-highlight):not(.p-disabled).p-focus {
|
||||
color: #212529;
|
||||
background: #dee2e6;
|
||||
}
|
||||
.p-listbox:not(.p-disabled) .p-listbox-item:not(.p-highlight):not(.p-disabled):hover {
|
||||
color: #212529;
|
||||
background: #e9ecef;
|
||||
}
|
||||
.p-listbox.p-focus {
|
||||
outline: 0 none;
|
||||
outline-offset: 0;
|
||||
}
|
||||
.p-listbox.p-invalid {
|
||||
border-color: #dc3545;
|
||||
}
|
37
resources/css/vue.css
Normal file
37
resources/css/vue.css
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
*/
|
||||
|
||||
.vueAction {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.flex-align-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.justify-self-start {
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
.gap-1 {
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.grid label {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.grid input {
|
||||
width: 100%;
|
||||
}
|
15
resources/js/ajaxErrorHandler.ts
Normal file
15
resources/js/ajaxErrorHandler.ts
Normal file
@ -0,0 +1,15 @@
|
||||
// SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import {AxiosError} from 'axios';
|
||||
|
||||
export function AlertErrorHandler(error: AxiosError) {
|
||||
if (error.response === undefined || error.response.status >= 500) {
|
||||
console.log('Unknown error on axios request', error);
|
||||
alert('Unerwarteter Fehler, weitere Hinweise ggf. in der JavaScript-Konsole');
|
||||
} else {
|
||||
console.log('ClientError on axios request', error);
|
||||
alert(error.response.data);
|
||||
}
|
||||
}
|
7
resources/js/jqueryBridge.js
vendored
Normal file
7
resources/js/jqueryBridge.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
export function reloadDataTables() {
|
||||
window.$('#main .dataTable').DataTable().ajax.reload();
|
||||
}
|
12
resources/js/vue.js
Normal file
12
resources/js/vue.js
Normal file
@ -0,0 +1,12 @@
|
||||
// SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
//
|
||||
// SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
|
||||
import '@res/css/vue.css';
|
||||
import '@res/css/primevue/_base.css';
|
||||
import {createApp} from "vue";
|
||||
import PrimeVue from "primevue/config";
|
||||
|
||||
export function createVueApp(rootComponent, rootProps) {
|
||||
return createApp(rootComponent, rootProps).use(PrimeVue);
|
||||
}
|
44
resources/vue/AutoComplete.vue
Normal file
44
resources/vue/AutoComplete.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
import AutoComplete from "primevue/autocomplete";
|
||||
import axios from "axios";
|
||||
|
||||
const props = defineProps({
|
||||
ajaxFilter: String,
|
||||
modelValue: null,
|
||||
forceSelection: Boolean
|
||||
});
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const items = ref([]);
|
||||
async function search(event) {
|
||||
await axios.get('index.php',
|
||||
{
|
||||
params: {
|
||||
module: 'ajax',
|
||||
action: 'filter',
|
||||
filtername: props.ajaxFilter,
|
||||
term: event.query,
|
||||
object: true
|
||||
}
|
||||
})
|
||||
.then(response => items.value = response.data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AutoComplete
|
||||
:modelValue="modelValue"
|
||||
@update:modelValue="value => emit('update:modelValue', value)"
|
||||
:suggestions="items"
|
||||
@complete="search"
|
||||
dataKey="id"
|
||||
:forceSelection="forceSelection"
|
||||
/>
|
||||
</template>
|
31
vite.config.js
Normal file
31
vite.config.js
Normal file
@ -0,0 +1,31 @@
|
||||
// SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import glob from 'glob';
|
||||
import path from 'path';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
|
||||
const moduleInputs = glob.sync('classes/Modules/*/www/js/entry.{js,jsx}')
|
||||
.map(file => ['modules/'+file.split('/')[2], file]);
|
||||
|
||||
/** @type {import('vite').UserConfig} */
|
||||
export default {
|
||||
build: {
|
||||
rollupOptions: {
|
||||
input: {
|
||||
...Object.fromEntries(moduleInputs)
|
||||
}
|
||||
},
|
||||
manifest: true,
|
||||
outDir: 'www/dist',
|
||||
},
|
||||
plugins: [vue()],
|
||||
mode: 'development',
|
||||
resolve: {
|
||||
alias: {
|
||||
'@theme': path.resolve(__dirname, 'www/themes/new/js'),
|
||||
'@res': path.resolve(__dirname, 'resources')
|
||||
}
|
||||
}
|
||||
}
|
1
www/dist/assets/entry-597722a1.css
vendored
Normal file
1
www/dist/assets/entry-597722a1.css
vendored
Normal file
File diff suppressed because one or more lines are too long
922
www/dist/assets/modules/MatrixProduct-1c46dcc9.js
vendored
Normal file
922
www/dist/assets/modules/MatrixProduct-1c46dcc9.js
vendored
Normal file
File diff suppressed because one or more lines are too long
14
www/dist/manifest.json
vendored
Normal file
14
www/dist/manifest.json
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"classes/Modules/MatrixProduct/www/js/entry.css": {
|
||||
"file": "assets/entry-597722a1.css",
|
||||
"src": "classes/Modules/MatrixProduct/www/js/entry.css"
|
||||
},
|
||||
"classes/Modules/MatrixProduct/www/js/entry.jsx": {
|
||||
"css": [
|
||||
"assets/entry-597722a1.css"
|
||||
],
|
||||
"file": "assets/modules/MatrixProduct-1c46dcc9.js",
|
||||
"isEntry": true,
|
||||
"src": "classes/Modules/MatrixProduct/www/js/entry.jsx"
|
||||
}
|
||||
}
|
@ -1875,7 +1875,6 @@ class Remote
|
||||
if(is_numeric($matrixPseudoStorage) && $matrixPseudoStorage < 0) {
|
||||
$matrixPseudoStorage = 0;
|
||||
}
|
||||
$matrixStock = (float)$this->app->erp->ArtikelAnzahlVerkaufbar($eigenschaft['artikel'], 0, $projektlager, $id, $lagergrundlage);
|
||||
if($matrixStock < 0) {
|
||||
$matrixStock = 0;
|
||||
}
|
||||
|
7
www/manifest.json
Normal file
7
www/manifest.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"classes/Modules/MatrixProduct/www/js/entry.js": {
|
||||
"file": "assets/modules/MatrixProduct-4ed993c7.js",
|
||||
"isEntry": true,
|
||||
"src": "classes/Modules/MatrixProduct/www/js/entry.js"
|
||||
}
|
||||
}
|
@ -1,4 +1,12 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Xentral ERP Software GmbH, Fuggerstrasse 11, D-86150 Augsburg
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
*/
|
||||
|
||||
/*
|
||||
**** COPYRIGHT & LICENSE NOTICE *** DO NOT REMOVE ****
|
||||
*
|
||||
@ -1218,6 +1226,7 @@ class Ajax {
|
||||
$rmodule = $this->app->Secure->GetGET('rmodule');
|
||||
$raction = $this->app->Secure->GetGET('raction');
|
||||
$rid = (int)$this->app->Secure->GetGET('rid');
|
||||
$asObject = $this->app->Secure->GetGET('object');
|
||||
$pruefemodule = array('artikel','auftrag','angebot','rechnung','lieferschein','gutschrift','bestellung','produktion');
|
||||
$filter_projekt = 0;
|
||||
if($raction === 'edit' && $rid && in_array($rmodule, $pruefemodule))
|
||||
@ -2529,15 +2538,19 @@ select a.kundennummer, (SELECT name FROM adresse a2 WHERE a2.kundennummer = a.ku
|
||||
//if($checkprojekt > 0 && $eigenernummernkreis=="1") $tmp_where = " AND projekt='$checkprojekt' ";
|
||||
//else $tmp_where = "";
|
||||
|
||||
|
||||
$selectfields = $asObject ? 'art.id, art.nummer, art.name_de name' : "CONCAT(nummer,' ',name_de) as `name`";
|
||||
$arr = $this->app->DB->SelectArr(
|
||||
"SELECT CONCAT(nummer,' ',name_de) as `name`
|
||||
FROM artikel AS art WHERE geloescht=0 AND ($subwhere) AND geloescht=0 AND intern_gesperrt!=1 $tmp_where ".
|
||||
"SELECT $selectfields
|
||||
FROM artikel AS art WHERE geloescht=0 AND ($subwhere) AND intern_gesperrt!=1 $tmp_where ".
|
||||
$this->app->erp->ProjektRechte('art.projekt'). ' LIMIT 20'
|
||||
);
|
||||
$carr = !empty($arr)?count($arr):0;
|
||||
for($i = 0; $i < $carr; $i++) {
|
||||
$newarr[] = $arr[$i]['name'];
|
||||
if ($asObject) {
|
||||
$newarr = $arr;
|
||||
} else {
|
||||
$carr = !empty($arr) ? count($arr) : 0;
|
||||
for ($i = 0; $i < $carr; $i++) {
|
||||
$newarr[] = $arr[$i]['name'];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -3867,11 +3880,16 @@ select a.kundennummer, (SELECT name FROM adresse a2 WHERE a2.kundennummer = a.ku
|
||||
}
|
||||
break;
|
||||
|
||||
case "projektname":
|
||||
$arr = $this->app->DB->SelectArr("SELECT CONCAT(p.abkuerzung,' ',p.name) as name FROM projekt p WHERE p.geloescht=0 AND status <> 'abgeschlossen' AND (p.name LIKE '%$term%' OR p.name LIKE '%$term2%' OR p.name LIKE '%$term3%' OR p.abkuerzung LIKE '%$term%' OR p.abkuerzung LIKE '%$term2%' OR p.abkuerzung LIKE '%$term3%') ".$this->app->erp->ProjektRechte());
|
||||
$carr = !empty($arr)?count($arr):0;
|
||||
for($i = 0; $i < $carr; $i++) {
|
||||
$newarr[] = $arr[$i]['name'];
|
||||
case "projektname":
|
||||
$fields = $asObject ? 'p.id, p.abkuerzung, p.name' : "CONCAT(p.abkuerzung,' ',p.name) as name";
|
||||
$arr = $this->app->DB->SelectArr("SELECT $fields FROM projekt p WHERE p.geloescht=0 AND status <> 'abgeschlossen' AND (p.name LIKE '%$term%' OR p.name LIKE '%$term2%' OR p.name LIKE '%$term3%' OR p.abkuerzung LIKE '%$term%' OR p.abkuerzung LIKE '%$term2%' OR p.abkuerzung LIKE '%$term3%') ".$this->app->erp->ProjektRechte());
|
||||
if ($asObject) {
|
||||
$newarr = $arr;
|
||||
} else {
|
||||
$carr = !empty($arr) ? count($arr) : 0;
|
||||
for ($i = 0; $i < $carr; $i++) {
|
||||
$newarr[] = $arr[$i]['name'];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -4185,7 +4203,16 @@ select a.kundennummer, (SELECT name FROM adresse a2 WHERE a2.kundennummer = a.ku
|
||||
}else{
|
||||
$cnewarr = !empty($newarr)?count($newarr):0;
|
||||
for($i=0;$i<$cnewarr;$i++) {
|
||||
$tmp[] = $this->app->erp->ClearDataBeforeOutput(html_entity_decode($newarr[$i], ENT_QUOTES, 'UTF-8'));
|
||||
$row = $newarr[$i];
|
||||
if (is_string($row))
|
||||
$tmp[] = $this->app->erp->ClearDataBeforeOutput(html_entity_decode($newarr[$i], ENT_QUOTES, 'UTF-8'));
|
||||
else if (is_array($row)) {
|
||||
$tmprow = [];
|
||||
foreach ($row as $key => $value) {
|
||||
$tmprow[$key] = $this->app->erp->ClearDataBeforeOutput(html_entity_decode($value, ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
$tmp[] = $tmprow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,12 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Xentral ERP Software GmbH, Fuggerstrasse 11, D-86150 Augsburg
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
*/
|
||||
|
||||
/*
|
||||
**** COPYRIGHT & LICENSE NOTICE *** DO NOT REMOVE ****
|
||||
*
|
||||
@ -7320,6 +7328,10 @@ class Artikel extends GenArtikel {
|
||||
$this->app->erp->MenuEintrag('index.php?module=artikel&action=eigenschaften&id='.$id, 'Eigenschaften');
|
||||
}
|
||||
|
||||
if ($tmp[0]['matrixprodukt']==1) {
|
||||
$this->app->erp->MenuEintrag("index.php?module=matrixprodukt&action=artikel&id=$id", 'Matrixprodukt');
|
||||
}
|
||||
|
||||
if($rabatt!='1'){
|
||||
$this->app->erp->MenuEintrag("index.php?module=artikel&action=einkauf&id=$id",'Einkauf');
|
||||
if($this->app->erp->RechteVorhanden('einkaufabgleich','einkaufapi'))
|
||||
|
58
www/pages/content/matrixprodukt_article.tpl
Normal file
58
www/pages/content/matrixprodukt_article.tpl
Normal file
@ -0,0 +1,58 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
-->
|
||||
|
||||
<div id="tabs">
|
||||
<ul>
|
||||
<li><a href="#tabs-1">Gruppen/Optionen</a></li>
|
||||
<li><a href="#tabs-2">Variantenzuordnung</a></li>
|
||||
</ul>
|
||||
<div id="tabs-1">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-10 col-md-height">
|
||||
<div class="inside-white inside-full-height">
|
||||
[MESSAGE]
|
||||
[TAB1]
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-2 col-md-height">
|
||||
<div class="inside inside-full-height">
|
||||
<fieldset>
|
||||
<legend>{|Aktionen|}</legend>
|
||||
<input type="button" class="btnGreenNew vueAction" data-action="addGlobalToArticle" data-article-id="[ID]" value="✚ Optionen übernehmen">
|
||||
<input type="button" class="btnGreenNew vueAction" data-action="[ADDEDITFUNCTION]" data-group-id="[SID]" data-article-id="[ID]" value="✚ Neuer Eintrag">
|
||||
<input type="button" class="btnGreenNew" name="matrixprodukt_module"
|
||||
value="➜ Vordefinierte Gruppen/Optionen" onclick="window.location.href='index.php?module=matrixprodukt&action=list';">
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tabs-2">
|
||||
<div class="row">
|
||||
<div class="row-height">
|
||||
<div class="col-xs-12 col-md-10 col-md-height">
|
||||
<div class="inside-white inside-full-height">
|
||||
[MESSAGE]
|
||||
[TAB2]
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-2 col-md-height">
|
||||
<div class="inside inside-full-height">
|
||||
<fieldset>
|
||||
<legend>{|Aktionen|}</legend>
|
||||
<input type="button" class="btnGreenNew vueAction" data-action="variantEdit" data-article-id="[ID]" value="✚ Neue Variante">
|
||||
<!--<input type="button" class="btnGreenNew vueAction" data-action="createMissing" data-article-id="[ID]" value="✚ Erzeuge fehlende Varianten">-->
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- tab view schließen -->
|
||||
</div>
|
||||
<!-- ende tab view schließen -->
|
||||
|
||||
<div id="vueapp"></div>
|
@ -1,5 +1,8 @@
|
||||
<!-- gehort zu tabview -->
|
||||
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
SPDX-FileCopyrightText: 2019 Xentral (c) Xentral ERP Software GmbH, Fuggerstrasse 11, D-86150 Augsburg, Germany
|
||||
SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
-->
|
||||
<div id="tabs">
|
||||
<ul>
|
||||
<li><a href="#tabs-1">[TABTEXT]</a></li>
|
||||
@ -29,33 +32,7 @@
|
||||
</div>
|
||||
<!-- ende tab view schließen -->
|
||||
|
||||
|
||||
<div id="editMatrixprodukt" style="display:none;" title="Bearbeiten">
|
||||
<form action="" method="post" name="eprooform">
|
||||
<input type="hidden" id="matrixprodukt_id">
|
||||
<fieldset>
|
||||
<legend>{|Einstellungen|}</legend>
|
||||
<table>
|
||||
<tr>
|
||||
<td width="100">{|Name|}:</td>
|
||||
<td><input type="text" size="40" name="matrixprodukt_name" id="matrixprodukt_name"></td>
|
||||
</tr>
|
||||
<tr[STYLEEXT]>
|
||||
<td>{|Name Extern|}:</td>
|
||||
<td><input type="text" size="40" name="matrixprodukt_name_ext" id="matrixprodukt_name_ext"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{|Projekt|}:</td>
|
||||
<td><input type="text" size="40" name="matrixprodukt_projekt" id="matrixprodukt_projekt"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{|Aktiv|}:</td>
|
||||
<td><input type="checkbox" name="matrixprodukt_aktiv" id="matrixprodukt_aktiv" value="1"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<div id="vueapp"></div>
|
||||
|
||||
<div id="editMatrixproduktUebersetzung" style="display:none;" title="Bearbeiten">
|
||||
<form action="" method="post" name="eprooform">
|
||||
@ -115,56 +92,6 @@
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#matrixprodukt_name').focus();
|
||||
|
||||
$("#editMatrixprodukt").dialog({
|
||||
modal: true,
|
||||
bgiframe: true,
|
||||
closeOnEscape:false,
|
||||
minWidth:500,
|
||||
maxHeight:800,
|
||||
autoOpen: false,
|
||||
buttons: {
|
||||
ABBRECHEN: function() {
|
||||
MatrixproduktReset();
|
||||
$(this).dialog('close');
|
||||
},
|
||||
SPEICHERN: function() {
|
||||
MatrixproduktEditSave();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$("#editMatrixprodukt").dialog({
|
||||
close: function( event, ui ) {MatrixproduktReset();}
|
||||
});
|
||||
|
||||
$("#editMatrixproduktUebersetzung").dialog({
|
||||
modal: true,
|
||||
bgiframe: true,
|
||||
closeOnEscape:false,
|
||||
minWidth:500,
|
||||
maxHeight:800,
|
||||
autoOpen: false,
|
||||
buttons: {
|
||||
ABBRECHEN: function() {
|
||||
MatrixproduktUebersetzungReset();
|
||||
$(this).dialog('close');
|
||||
},
|
||||
SPEICHERN: function() {
|
||||
MatrixproduktUebersetzungEditSave();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$("#editMatrixproduktUebersetzung").dialog({
|
||||
close: function( event, ui ) {MatrixproduktUebersetzungReset();}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function MatrixproduktUebersetzungReset(){
|
||||
$('#editMatrixproduktUebersetzung').find('#matrixprodukt_uebersetzung_id').val('');
|
||||
$('#editMatrixproduktUebersetzung').find('#matrixprodukt_sprache_von').val('');
|
||||
@ -277,111 +204,5 @@ function MatrixproduktUebersetzungDelete(id) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function MatrixproduktReset(){
|
||||
$('#editMatrixprodukt').find('#matrixprodukt_id').val('');
|
||||
$('#editMatrixprodukt').find('#matrixprodukt_name').val('');
|
||||
$('#editMatrixprodukt').find('#matrixprodukt_name_ext').val('');
|
||||
$('#editMatrixprodukt').find('#matrixprodukt_projekt').val('');
|
||||
$('#editMatrixprodukt').find('#matrixprodukt_aktiv').prop("checked", true);
|
||||
}
|
||||
|
||||
function MatrixproduktEditSave() {
|
||||
|
||||
$.ajax({
|
||||
url: 'index.php?module=matrixprodukt&action=list&cmd=save',
|
||||
data: {
|
||||
//Alle Felder die fürs editieren vorhanden sind
|
||||
id: $('#matrixprodukt_id').val(),
|
||||
name: $('#matrixprodukt_name').val(),
|
||||
name_ext: $('#matrixprodukt_name_ext').val(),
|
||||
projekt: $('#matrixprodukt_projekt').val(),
|
||||
aktiv: $('#matrixprodukt_aktiv').prop("checked")?1:0
|
||||
|
||||
},
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
beforeSend: function() {
|
||||
App.loading.open();
|
||||
},
|
||||
success: function(data) {
|
||||
App.loading.close();
|
||||
if (data.status == 1) {
|
||||
MatrixproduktReset();
|
||||
updateLiveTable();
|
||||
$("#editMatrixprodukt").dialog('close');
|
||||
} else {
|
||||
alert(data.statusText);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function MatrixproduktEdit(id) {
|
||||
if(id > 0)
|
||||
{
|
||||
$.ajax({
|
||||
url: 'index.php?module=matrixprodukt&action=list&cmd=edit',
|
||||
data: {
|
||||
id: id
|
||||
},
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
beforeSend: function() {
|
||||
App.loading.open();
|
||||
},
|
||||
success: function(data) {
|
||||
$('#editMatrixprodukt').find('#matrixprodukt_id').val(data.id);
|
||||
$('#editMatrixprodukt').find('#matrixprodukt_name').val(data.name);
|
||||
$('#editMatrixprodukt').find('#matrixprodukt_name_ext').val(data.name_ext);
|
||||
$('#editMatrixprodukt').find('#matrixprodukt_projekt').val(data.projekt);
|
||||
$('#editMatrixprodukt').find('#matrixprodukt_aktiv').prop("checked",data.aktiv==1?true:false);
|
||||
|
||||
App.loading.close();
|
||||
$("#editMatrixprodukt").dialog('open');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
MatrixproduktReset();
|
||||
$("#editMatrixprodukt").dialog('open');
|
||||
}
|
||||
}
|
||||
|
||||
function updateLiveTable(i) {
|
||||
var oTableL = $('#matrixprodukt_eigenschaftengruppen').dataTable();
|
||||
var tmp = $('.dataTables_filter input[type=search]').val();
|
||||
oTableL.fnFilter('%');
|
||||
//oTableL.fnFilter('');
|
||||
oTableL.fnFilter(tmp);
|
||||
}
|
||||
|
||||
function MatrixproduktDelete(id) {
|
||||
var conf = confirm('Wirklich löschen?');
|
||||
if (conf) {
|
||||
$.ajax({
|
||||
url: 'index.php?module=matrixprodukt&action=list&cmd=delete',
|
||||
data: {
|
||||
id: id
|
||||
},
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
beforeSend: function() {
|
||||
App.loading.open();
|
||||
},
|
||||
success: function(data) {
|
||||
if(data.status == 1){
|
||||
updateLiveTable();
|
||||
}else{
|
||||
alert(data.statusText);
|
||||
}
|
||||
App.loading.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -1,12 +1,14 @@
|
||||
<!-- gehort zu tabview -->
|
||||
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
SPDX-FileCopyrightText: 2019 Xentral (c) Xentral ERP Software GmbH, Fuggerstrasse 11, D-86150 Augsburg, Germany
|
||||
SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
-->
|
||||
<div id="tabs">
|
||||
<ul>
|
||||
<li><a href="#tabs-1">[TABTEXT]</a></li>
|
||||
</ul>
|
||||
<!-- erstes tab -->
|
||||
<div id="tabs-1">
|
||||
|
||||
<div class="row">
|
||||
<div class="row-height">
|
||||
<div class="col-xs-12 col-md-10 col-md-height">
|
||||
@ -19,7 +21,7 @@
|
||||
<div class="inside inside-full-height">
|
||||
<fieldset>
|
||||
<legend>{|Aktionen|}</legend>
|
||||
<input type="button" class="btnGreenNew" name="neueoption" value="✚ Neuer Eintrag" onclick="MatrixproduktOptionenEdit(0);">
|
||||
<input type="button" class="btnGreenNew" name="neueoption" data-action="optionEdit" data-option-id="0" value="✚ Neuer Eintrag" onclick="MatrixproduktOptionenEdit(0);">
|
||||
<input type="button" class="btnGreenNew" name="neueuebersetzung" value="✚ Neue Übersetzung" onclick="MatrixproduktOptionenUebersetzungEdit(0);">
|
||||
</fieldset>
|
||||
</div>
|
||||
@ -32,37 +34,7 @@
|
||||
</div>
|
||||
<!-- ende tab view schließen -->
|
||||
|
||||
<div id="editMatrixproduktOptionen" style="display:none;" title="Bearbeiten">
|
||||
<form action="" method="post" name="eprooform" >
|
||||
<input type="hidden" id="matrixprodukt_optionen_id">
|
||||
<input type="hidden" name = "matrixprodukt_eintragid" id="matrixprodukt_eintragid" value="[ID]">
|
||||
<fieldset>
|
||||
<legend>{|Einstellungen|}</legend>
|
||||
<table>
|
||||
<tr>
|
||||
<td width="100">{|Name|}:</td>
|
||||
<td><input type="text" size="40" name="matrixprodukt_optionen_name" id="matrixprodukt_optionen_name"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="100">{|Anhang an Artikelnummer|}:</td>
|
||||
<td><input type="text" size="40" name="matrixprodukt_optionen_articlenumber_suffix" id="matrixprodukt_optionen_articlenumber_suffix"></td>
|
||||
</tr>
|
||||
<tr[STYLEEXT]>
|
||||
<td>{|Name Extern|}:</td>
|
||||
<td><input type="text" size="40" name="matrixprodukt_optionen_name_ext" id="matrixprodukt_optionen_name_ext"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{|Sortierung|}:</td>
|
||||
<td><input type="text" size="8" name="matrixprodukt_optionen_sortierung" id="matrixprodukt_optionen_sortierung"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{|Aktiv|}:</td>
|
||||
<td><input type="checkbox" name="matrixprodukt_optionen_aktiv" id="matrixprodukt_optionen_aktiv" value="1"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<div id="vueapp"></div>
|
||||
|
||||
<div id="editMatrixproduktOptionenUebersetzung" style="display:none;" title="Bearbeiten">
|
||||
<form action="" method="post" name="eprooform">
|
||||
@ -119,33 +91,7 @@
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#matrixprodukt_optionen_name').focus();
|
||||
|
||||
$("#editMatrixproduktOptionen").dialog({
|
||||
modal: true,
|
||||
bgiframe: true,
|
||||
closeOnEscape:false,
|
||||
minWidth:500,
|
||||
maxHeight:800,
|
||||
autoOpen: false,
|
||||
buttons: {
|
||||
ABBRECHEN: function() {
|
||||
MatrixproduktOptionenReset();
|
||||
$(this).dialog('close');
|
||||
},
|
||||
SPEICHERN: function() {
|
||||
MatrixproduktOptionenEditSave();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$("#editMatrixproduktOptionen").dialog({
|
||||
close: function( event, ui ) {MatrixproduktOptionenReset();}
|
||||
});
|
||||
|
||||
|
||||
$("#editMatrixproduktOptionenUebersetzung").dialog({
|
||||
modal: true,
|
||||
bgiframe: true,
|
||||
@ -282,117 +228,5 @@ function MatrixproduktOptionenUebersetzungDelete(id) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function MatrixproduktOptionenReset(){
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_id').val('');
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_name').val('');
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_name_ext').val('');
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_articlenumber_suffix').val('');
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_sortierung').val('');
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_aktiv').prop("checked", true);
|
||||
}
|
||||
|
||||
function MatrixproduktOptionenEditSave() {
|
||||
|
||||
$.ajax({
|
||||
url: 'index.php?module=matrixprodukt&action=optionenlist&cmd=optionensave',
|
||||
data: {
|
||||
//Alle Felder die fürs editieren vorhanden sind
|
||||
optionenid: $('#matrixprodukt_optionen_id').val(),
|
||||
matrixproduktid: $('#matrixprodukt_eintragid').val(),
|
||||
optionenname: $('#matrixprodukt_optionen_name').val(),
|
||||
optionenarticlenumber_suffix: $('#matrixprodukt_optionen_articlenumber_suffix').val(),
|
||||
optionenname_ext: $('#matrixprodukt_optionen_name_ext').val(),
|
||||
optionensortierung: $('#matrixprodukt_optionen_sortierung').val(),
|
||||
optionenaktiv: $('#matrixprodukt_optionen_aktiv').prop("checked")?1:0
|
||||
|
||||
},
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
beforeSend: function() {
|
||||
App.loading.open();
|
||||
},
|
||||
success: function(data) {
|
||||
App.loading.close();
|
||||
if (data.status == 1) {
|
||||
MatrixproduktOptionenReset();
|
||||
updateLiveTableOptionen();
|
||||
$("#editMatrixproduktOptionen").dialog('close');
|
||||
} else {
|
||||
alert(data.statusText);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function MatrixproduktOptionenEdit(id) {
|
||||
|
||||
if(id > 0)
|
||||
{
|
||||
$.ajax({
|
||||
url: 'index.php?module=matrixprodukt&action=optionenlist&cmd=optionenedit',
|
||||
data: {
|
||||
id: id
|
||||
},
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
beforeSend: function() {
|
||||
App.loading.open();
|
||||
},
|
||||
success: function(data) {
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_id').val(data.opt_id);
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_name').val(data.opt_name);
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_articlenumber_suffix').val(data.opt_articlenumber_suffix);
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_name_ext').val(data.opt_name_ext);
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_sortierung').val(data.opt_sortierung);
|
||||
$('#editMatrixproduktOptionen').find('#matrixprodukt_optionen_aktiv').prop("checked",data.opt_aktiv==1?true:false);
|
||||
|
||||
App.loading.close();
|
||||
$("#editMatrixproduktOptionen").dialog('open');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
MatrixproduktOptionenReset();
|
||||
$("#editMatrixproduktOptionen").dialog('open');
|
||||
}
|
||||
}
|
||||
|
||||
function updateLiveTableOptionen(i) {
|
||||
var oTableL = $('#matrixprodukt_eigenschaftenoptionen').dataTable();
|
||||
var tmp = $('.dataTables_filter input[type=search]').val();
|
||||
oTableL.fnFilter('%');
|
||||
//oTableL.fnFilter('');
|
||||
oTableL.fnFilter(tmp);
|
||||
}
|
||||
|
||||
function MatrixproduktOptionenDelete(id) {
|
||||
var conf = confirm('Wirklich löschen?');
|
||||
if (conf) {
|
||||
$.ajax({
|
||||
url: 'index.php?module=matrixprodukt&action=optionenlist&cmd=optionendelete',
|
||||
data: {
|
||||
id: id
|
||||
},
|
||||
method: 'post',
|
||||
dataType: 'json',
|
||||
beforeSend: function() {
|
||||
App.loading.open();
|
||||
},
|
||||
success: function(data) {
|
||||
if(data.status == 1){
|
||||
updateLiveTableOptionen();
|
||||
}else{
|
||||
alert(data.statusText);
|
||||
}
|
||||
App.loading.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
346
www/pages/matrixprodukt.php
Normal file
346
www/pages/matrixprodukt.php
Normal file
@ -0,0 +1,346 @@
|
||||
<?php
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
* SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
*/
|
||||
|
||||
use Xentral\Components\Http\JsonResponse;
|
||||
use Xentral\Components\Http\Request;
|
||||
use Xentral\Components\Http\Response;
|
||||
use Xentral\Modules\MatrixProduct\Data\Group;
|
||||
use Xentral\Modules\MatrixProduct\Data\Option;
|
||||
use Xentral\Modules\MatrixProduct\MatrixProductService;
|
||||
|
||||
class Matrixprodukt
|
||||
{
|
||||
private ApplicationCore $app;
|
||||
private MatrixProductService $service;
|
||||
private Request $request;
|
||||
|
||||
const MODULE_NAME = 'MatrixProduct';
|
||||
|
||||
public function __construct(ApplicationCore $app, bool $intern = false)
|
||||
{
|
||||
$this->app = $app;
|
||||
if ($intern)
|
||||
return;
|
||||
|
||||
if (!$this->app instanceof Application)
|
||||
return;
|
||||
$this->service = $this->app->Container->get('MatrixProductService');
|
||||
$this->request = $this->app->Container->get('Request');
|
||||
|
||||
$this->app->ActionHandlerInit($this);
|
||||
$this->app->ActionHandler("list", "ActionList");
|
||||
$this->app->ActionHandler("optionenlist", "ActionOptionList");
|
||||
$this->app->ActionHandler("artikel", "ActionArticle");
|
||||
$this->app->ActionHandlerListen($app);
|
||||
}
|
||||
|
||||
private function createMenu(): void
|
||||
{
|
||||
$this->app->erp->MenuEintrag("index.php?module=matrixprodukt&action=list", "Übersicht");
|
||||
}
|
||||
|
||||
public function Install()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function TableSearch(&$app, $name, $erlaubtevars)
|
||||
{
|
||||
switch ($name) {
|
||||
case "matrixprodukt_groups":
|
||||
$allowed['matrixprodukt_list'] = array('list');
|
||||
$heading = array('', 'Name', 'Name (extern)', 'Menü');
|
||||
$width = array('1%', '30%', '30%', '1%'); // Fill out manually later
|
||||
$findcols = array('mg.id', 'mg.name', 'mg.name_ext');
|
||||
$searchsql = array('mg.name', 'mg.name_ext');
|
||||
$menu = "<table><tr><td nowrap>"
|
||||
. "<img class=\"vueAction\" data-action=\"groupEdit\" data-group-id=\"%value%\" src=\"./themes/{$app->Conf->WFconf['defaulttheme']}/images/edit.svg\"> "
|
||||
. "<a href=\"index.php?module=matrixprodukt&action=optionenlist&id=%value%\">"
|
||||
. "<img src=\"themes/{$app->Conf->WFconf['defaulttheme']}/images/forward.svg\"></a> "
|
||||
. "<img class=\"vueAction\" data-action=\"groupDelete\" data-group-id=\"%value%\" src=\"themes/{$app->Conf->WFconf['defaulttheme']}/images/delete.svg\">"
|
||||
. "</td></tr></table>";
|
||||
$sql = "SELECT SQL_CALC_FOUND_ROWS mg.id, mg.id, mg.name, mg.name_ext, mg.id FROM matrixprodukt_eigenschaftengruppen mg";
|
||||
$where = "1";
|
||||
$count = "SELECT count(DISTINCT id) FROM matrixprodukt_eigenschaftengruppen WHERE $where";
|
||||
break;
|
||||
case "matrixprodukt_options":
|
||||
$id = $this->app->Secure->GetGET('id');
|
||||
$heading = array('', 'Name', 'Name (extern)', 'Menü');
|
||||
$width = array('1%', '30%', '30%', '1%');
|
||||
$findcols = array('mo.id', 'mo.name', 'mo.name_ext');
|
||||
$searchsql = array('mo.name', 'mo.name_ext');
|
||||
$menu = "<table><tr><td nowrap>"
|
||||
. "<img class=\"vueAction\" data-action=\"optionEdit\" data-option-id=\"%value%\" src=\"./themes/{$app->Conf->WFconf['defaulttheme']}/images/edit.svg\"> "
|
||||
. "<img class=\"vueAction\" data-action=\"optionDelete\" data-option-id=\"%value%\" src=\"themes/{$app->Conf->WFconf['defaulttheme']}/images/delete.svg\">"
|
||||
. "</td></tr></table>";
|
||||
$sql = "SELECT SQL_CALC_FOUND_ROWS mo.id, mo.id, mo.name, mo.name_ext, mo.id FROM matrixprodukt_eigenschaftenoptionen mo";
|
||||
$where = "mo.gruppe = $id";
|
||||
$count = "SELECT count(DISTINCT mo.id) FROM matrixprodukt_eigenschaftenoptionen mo WHERE $where";
|
||||
break;
|
||||
case "matrixprodukt_article_groups":
|
||||
$id = $this->app->Secure->GetGET('id');
|
||||
$heading = array('', 'Name', 'Name (extern)', 'Menü');
|
||||
$width = array('1%', '30%', '30%', '1%'); // Fill out manually later
|
||||
$findcols = array('mga.id', 'mga.name', 'mga.name_ext');
|
||||
$searchsql = array('mga.name', 'mga.name_ext');
|
||||
$menu = "<table><tr><td nowrap>"
|
||||
. "<img class=\"vueAction\" data-action=\"groupEdit\" data-group-id=\"%value%\" data-article-id=\"$id\" src=\"./themes/{$app->Conf->WFconf['defaulttheme']}/images/edit.svg\"> "
|
||||
. "<a href=\"index.php?module=matrixprodukt&action=artikel&id=$id&sid=%value%\">"
|
||||
. "<img src=\"themes/{$app->Conf->WFconf['defaulttheme']}/images/forward.svg\"></a> "
|
||||
. "<img class=\"vueAction\" data-action=\"groupDelete\" data-group-id=\"%value%\" data-article-id=\"$id\" src=\"themes/{$app->Conf->WFconf['defaulttheme']}/images/delete.svg\">"
|
||||
. "</td></tr></table>";
|
||||
$sql = "SELECT SQL_CALC_FOUND_ROWS mga.id, mga.id, mga.name, mga.name_ext, mga.id FROM matrixprodukt_eigenschaftengruppen_artikel mga";
|
||||
$where = "mga.artikel = $id";
|
||||
$count = "SELECT count(DISTINCT mga.id) FROM matrixprodukt_eigenschaftengruppen_artikel mga WHERE $where";
|
||||
break;
|
||||
case "matrixprodukt_article_options":
|
||||
$id = $this->app->Secure->GetGET('id');
|
||||
$groupId = $this->app->Secure->GetGET('sid');
|
||||
$heading = array('', 'Name', 'Name (extern)', 'Menü');
|
||||
$width = array('1%', '30%', '30%', '1%');
|
||||
$findcols = array('moa.id', 'moa.name', 'moa.name_ext');
|
||||
$searchsql = array('moa.name', 'moa.name_ext');
|
||||
$menu = "<table><tr><td nowrap>"
|
||||
. "<img class=\"vueAction\" data-action=\"optionEdit\" data-option-id=\"%value%\" data-article-id=\"$id\" src=\"./themes/{$app->Conf->WFconf['defaulttheme']}/images/edit.svg\"> "
|
||||
. "<img class=\"vueAction\" data-action=\"optionDelete\" data-option-id=\"%value%\" data-article-id=\"$id\" src=\"themes/{$app->Conf->WFconf['defaulttheme']}/images/delete.svg\">"
|
||||
. "</td></tr></table>";
|
||||
$sql = "SELECT SQL_CALC_FOUND_ROWS moa.id, moa.id, moa.name, moa.name_ext, moa.id FROM matrixprodukt_eigenschaftenoptionen_artikel moa";
|
||||
$where = "moa.gruppe = $groupId";
|
||||
$count = "SELECT count(DISTINCT moa.id) FROM matrixprodukt_eigenschaftenoptionen_artikel moa WHERE $where";
|
||||
break;
|
||||
case "matrixprodukt_variants":
|
||||
$id = $this->app->Secure->GetGET('id');
|
||||
$groups = $this->app->DB->SelectPairs("SELECT id, name FROM matrixprodukt_eigenschaftengruppen_artikel WHERE artikel = $id");
|
||||
$heading[] = 'Artikel';
|
||||
$width[] = '5%';
|
||||
$nameColumns = [];
|
||||
$optIdColumns = [];
|
||||
$optNameColumns = [];
|
||||
$optFrom = [];
|
||||
$optWhere = [];
|
||||
foreach ($groups as $groupId => $groupName) {
|
||||
$heading[] = $groupName;
|
||||
$width[] = '5%';
|
||||
$nameColumns[] = "name_$groupId";
|
||||
$optIdColumns[] = "moa_$groupId.id";
|
||||
$optNameColumns[] = "moa_$groupId.name as name_$groupId";
|
||||
$optFrom[] = "matrixprodukt_eigenschaftenoptionen_artikel moa_$groupId";
|
||||
$optWhere[] = "moa_$groupId.artikel = $id AND moa_$groupId.gruppe = $groupId";
|
||||
}
|
||||
$heading[] = 'Menü';
|
||||
$width[] = '1%';
|
||||
$findcols = array_merge($nameColumns, ['nummer']);
|
||||
$searchsql = $nameColumns;
|
||||
$menu = "<table><tr><td nowrap>"
|
||||
. "<img class=\"vueAction\" data-action=\"variantEdit\" data-variant-id=\"%value%\" data-article-id=\"$id\" src=\"./themes/{$app->Conf->WFconf['defaulttheme']}/images/edit.svg\"> "
|
||||
. "<img class=\"vueAction\" data-action=\"variantDelete\" data-variant-id=\"%value%\" data-article-id=\"$id\" src=\"themes/{$app->Conf->WFconf['defaulttheme']}/images/delete.svg\">"
|
||||
. "</td></tr></table>";
|
||||
$optsqlIdCols = join(',', $optIdColumns);
|
||||
$optsqlNameCols = join(',', $optNameColumns);
|
||||
$optsqlFrom = join(' JOIN ', $optFrom);
|
||||
$optsqlWhere = join(' AND ', $optWhere);
|
||||
$optsql = "SELECT CONCAT_WS(',', $optsqlIdCols) idlist, $optsqlNameCols
|
||||
FROM $optsqlFrom WHERE $optsqlWhere";
|
||||
$artsql = "SELECT a.id, a.nummer, group_concat(mota.option_id order by mota.option_id separator ',') idlist
|
||||
FROM matrixprodukt_optionen_zu_artikel mota
|
||||
JOIN artikel a ON mota.artikel = a.id WHERE a.variante_von = $id group by mota.artikel";
|
||||
$sqlNameCols = join(',', $nameColumns);
|
||||
$sql = "SELECT SQL_CALC_FOUND_ROWS art.id, art.nummer, $sqlNameCols, art.id
|
||||
FROM ($artsql) art
|
||||
LEFT OUTER JOIN ($optsql) opts ON opts.idlist = art.idlist";
|
||||
$where = "1";
|
||||
//$count = "SELECT count(DISTINCT moa.id)
|
||||
// FROM matrixprodukt_eigenschaftengruppen_artikel mga
|
||||
// LEFT OUTER JOIN matrixprodukt_eigenschaftenoptionen_artikel moa on moa.gruppe = mga.id WHERE $where";
|
||||
break;
|
||||
}
|
||||
|
||||
$erg = false;
|
||||
foreach ($erlaubtevars as $k => $v) {
|
||||
if (isset($$v)) {
|
||||
$erg[$v] = $$v;
|
||||
}
|
||||
}
|
||||
return $erg;
|
||||
}
|
||||
|
||||
public function ActionList()
|
||||
{
|
||||
$cmd = $this->app->Secure->GetGET('cmd');
|
||||
switch ($cmd) {
|
||||
case "edit":
|
||||
$id = intval($this->app->Secure->GetGET('groupId'));
|
||||
$group = $this->service->GetGlobalGroupById($id);
|
||||
if (!$group)
|
||||
return JsonResponse::NotFound();
|
||||
$group->project = $this->app->DB->SelectRow("SELECT id, abkuerzung, name FROM projekt WHERE id = $group->projectId");
|
||||
return new JsonResponse($group);
|
||||
case "save":
|
||||
$json = $this->request->getJson();
|
||||
$group = new Group($json->name, $json->id ?? null, $json->active ?? false, $json->nameExternal ?? '', $json->project->id ?? 0, $json->required ?? false);
|
||||
$this->service->SaveGlobalGroup($group);
|
||||
return JsonResponse::NoContent();
|
||||
case "delete":
|
||||
$json = $this->request->getJson();
|
||||
$this->service->DeleteGlobalGroup($json->groupId);
|
||||
return JsonResponse::NoContent();
|
||||
case "selectoptions":
|
||||
$result = [];
|
||||
$sql = "SELECT mg.id groupid, mg.name groupname, mo.id optionid, mo.name optionname FROM matrixprodukt_eigenschaftengruppen mg JOIN matrixprodukt_eigenschaftenoptionen mo ON mo.gruppe = mg.id WHERE mg.aktiv = 1 AND mo.aktiv = 1";
|
||||
foreach ($this->app->DB->SelectArr($sql) as $row) {
|
||||
$groupid = $row['groupid'];
|
||||
if (!in_array($groupid, $result)) {
|
||||
$result[$groupid]['id'] = $groupid;
|
||||
$result[$groupid]['name'] = $row['groupname'];
|
||||
}
|
||||
$result[$groupid]['options'][] = ['id' => $row['optionid'], 'name' => $row['optionname']];
|
||||
}
|
||||
return new JsonResponse(array_values($result));
|
||||
}
|
||||
|
||||
$this->createMenu();
|
||||
$this->app->Tpl->Set('TABSADD', '<input type="button" class="neubutton vueAction" value="NEU" data-action="groupEdit">');
|
||||
$this->app->YUI->TableSearch('TAB1', 'matrixprodukt_groups', "show", "", "", basename(__FILE__), __CLASS__);
|
||||
$this->app->Tpl->Parse('PAGE', "matrixprodukt_list.tpl");
|
||||
}
|
||||
|
||||
public function ActionOptionList()
|
||||
{
|
||||
$id = $this->request->get->getInt('id');
|
||||
$cmd = $this->app->Secure->GetGET('cmd');
|
||||
switch ($cmd) {
|
||||
case "edit":
|
||||
$id = intval($this->app->Secure->GetGET('optionId'));
|
||||
$option = $this->service->GetGlobalOptionById($id);
|
||||
if (!$option)
|
||||
return JsonResponse::NotFound();
|
||||
return new JsonResponse($option);
|
||||
case "save":
|
||||
$json = $this->request->getJson();
|
||||
$option = new Option($json->name, $json->groupId, $json->id, $json->active ?? false,
|
||||
$json->nameExternal ?? '', $json->sort ?? 0, $json->articleNumber ?? '',
|
||||
$json->articleNumberSuffix ?? '');
|
||||
$this->service->SaveGlobalOption($option);
|
||||
return JsonResponse::NoContent();
|
||||
case "delete":
|
||||
$json = $this->request->getJson();
|
||||
$this->service->DeleteGlobalOption($json->optionId);
|
||||
return JsonResponse::NoContent();
|
||||
}
|
||||
|
||||
$this->app->Tpl->Set('TABSADD', '<input type="button" class="neubutton vueAction" value="NEU" data-action="optionEdit" data-group-id="' . $id . '">');
|
||||
$this->app->YUI->TableSearch('TAB1', 'matrixprodukt_options', "show", "", "", basename(__FILE__), __CLASS__);
|
||||
$this->app->Tpl->Parse('PAGE', "matrixprodukt_optionen_list.tpl");
|
||||
}
|
||||
|
||||
public function ActionArticle()
|
||||
{
|
||||
$cmd = $this->app->Secure->GetGET('cmd');
|
||||
$articleModule = $this->app->erp->LoadModul('artikel');
|
||||
$articleModule?->ArtikelMenu();
|
||||
switch ($cmd) {
|
||||
case "addoptions":
|
||||
$json = $this->request->getJson();
|
||||
$this->service->AddGlobalOptionsForArticle($json->articleId, $json->optionIds);
|
||||
return JsonResponse::NoContent();
|
||||
case "groupedit":
|
||||
$groupId = intval($this->app->Secure->GetGET('groupId'));
|
||||
if (!$groupId)
|
||||
return JsonResponse::NotFound();
|
||||
$group = $this->service->GetArticleGroupById($groupId);
|
||||
$group->project = $this->app->DB->SelectRow("SELECT id, abkuerzung, name FROM projekt WHERE id = $group->projectId");
|
||||
return new JsonResponse($group);
|
||||
case "groupsave":
|
||||
$json = $this->request->getJson();
|
||||
$group = new Group($json->name, $json->groupId, $json->active ?? false, $json->nameExternal ?? '',
|
||||
$json->project->id ?? 0, $json->required ?? false, $json->articleId, $json->sort ?? 0);
|
||||
$this->service->SaveArticleGroup($group);
|
||||
return JsonResponse::NoContent();
|
||||
case "groupdelete":
|
||||
$json = $this->request->getJson();
|
||||
if (!$this->service->DeleteArticleGroup($json->groupId))
|
||||
return JsonResponse::BadRequest(['error' => 'Die Gruppe wird noch von Variantenartikeln verwendet.']);
|
||||
return JsonResponse::NoContent();
|
||||
case "optionedit":
|
||||
$optionId = intval($this->app->Secure->GetGET('optionId'));
|
||||
$option = $this->service->GetArticleOptionById($optionId);
|
||||
if (!$option)
|
||||
return JsonResponse::NotFound();
|
||||
return new JsonResponse($option);
|
||||
case "optionsave":
|
||||
$json = $this->request->getJson();
|
||||
$option = new Option($json->name, $json->groupId, $json->optionId, $json->active ?? false,
|
||||
$json->nameExternal ?? '', $json->sort ?? 0, '',
|
||||
$json->articleNumberSuffix ?? '', 0, $json->articleId);
|
||||
$this->service->SaveArticleOption($option);
|
||||
return JsonResponse::NoContent();
|
||||
case "optiondelete":
|
||||
$json = $this->request->getJson();
|
||||
if (!$this->service->DeleteArticleOption($json->optionId))
|
||||
return JsonResponse::BadRequest(['error' => 'Die Option wird noch von Variantenartikeln verwendet.']);
|
||||
return JsonResponse::NoContent();
|
||||
case "variantedit":
|
||||
$articleId = $this->request->get->getInt('articleId');
|
||||
$variantId = $this->request->get->getInt('variantId');
|
||||
$groups = $this->service->GetArticleGroupsByArticleId($articleId);
|
||||
$options = $this->service->GetArticleOptionsByArticleId($articleId);
|
||||
$selected = $this->service->GetSelectedOptionIdsByVariantId($variantId);
|
||||
$result = [];
|
||||
foreach ($groups as $group) {
|
||||
$result[$group->id] = [
|
||||
'name' => $group->name,
|
||||
'selected' => 0,
|
||||
'options' => []
|
||||
];
|
||||
}
|
||||
foreach ($options as $option) {
|
||||
$result[$option->groupId]['options'][] = ['value' => $option->id, 'name' => $option->name];
|
||||
if (in_array($option->id, $selected))
|
||||
$result[$option->groupId]['selected'] = $option->id;
|
||||
}
|
||||
$variant = $this->app->DB->SelectRow("SELECT id, nummer, name_de FROM artikel WHERE id = $variantId");
|
||||
return new JsonResponse([
|
||||
'groups' => $result,
|
||||
'variant' => $variant
|
||||
]);
|
||||
case "variantsave":
|
||||
$json = $this->request->getJson();
|
||||
$optionIds = [];
|
||||
foreach ($json->groups as $group) {
|
||||
if ($group->selected > 0)
|
||||
$optionIds[] = intval($group->selected);
|
||||
}
|
||||
if (empty($optionIds))
|
||||
return JsonResponse::BadRequest();
|
||||
$res = $this->service->SaveVariant($json->articleId, $json->variant->id, $optionIds, $json->variantId);
|
||||
if ($res === true)
|
||||
return JsonResponse::NoContent();
|
||||
return new JsonResponse([$res], Response::HTTP_BAD_REQUEST);
|
||||
case "variantdelete":
|
||||
$json = $this->request->getJson();
|
||||
$this->service->DeleteVariant($json->variantId);
|
||||
return JsonResponse::NoContent();
|
||||
case "acarticles":
|
||||
$query = $this->app->Secure->GetGET('query');
|
||||
$result = $this->app->DB->SelectArr("SELECT id, nummer, name_de FROM artikel WHERE (nummer LIKE '%$query%' OR name_de LIKE '%$query%') AND geloescht = 0");
|
||||
return new JsonResponse($result);
|
||||
}
|
||||
|
||||
$groupId = $this->app->Secure->GetGET('sid');
|
||||
if (empty($groupId)) {
|
||||
$this->app->YUI->TableSearch('TAB1', 'matrixprodukt_article_groups', "show", "", "", basename(__FILE__), __CLASS__);
|
||||
$this->app->Tpl->Set('ADDEDITFUNCTION', 'groupEdit');
|
||||
} else {
|
||||
$articleId = $this->app->Secure->GetGET('id');
|
||||
$this->app->erp->MenuEintrag("index.php?module=matrixprodukt&action=artikel&id=$articleId", 'Zurück zur Gruppenübersicht');
|
||||
$this->app->YUI->TableSearch('TAB1', 'matrixprodukt_article_options', "show", "", "", basename(__FILE__), __CLASS__);
|
||||
$this->app->Tpl->Set('SID', $groupId);
|
||||
$this->app->Tpl->Set('ADDEDITFUNCTION', 'optionEdit');
|
||||
}
|
||||
$this->app->YUI->TableSearch('TAB2', 'matrixprodukt_variants', "show", "", "", basename(__FILE__), __CLASS__);
|
||||
$this->app->Tpl->Parse('PAGE', "matrixprodukt_article.tpl");
|
||||
}
|
||||
}
|
2
www/themes/new/css/normalize.min.css
vendored
2
www/themes/new/css/normalize.min.css
vendored
@ -1,2 +1,4 @@
|
||||
@layer reset {
|
||||
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}
|
||||
/*# sourceMappingURL=normalize.min.css.map */
|
||||
}
|
@ -1418,7 +1418,7 @@ ul.menu.merged[data-items='25'] > li { width: 4%; }
|
||||
}
|
||||
|
||||
|
||||
/* Clear Floated Elements
|
||||
/* Clear Floated Elements
|
||||
- - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
.clear {
|
||||
@ -1725,7 +1725,7 @@ fieldset.usersave div.filter-item > label {
|
||||
}
|
||||
|
||||
|
||||
/* Calendar
|
||||
/* Calendar
|
||||
- - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
|
@ -1,3 +1,10 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Andreas Palm
|
||||
SPDX-FileCopyrightText: 2019 Xentral ERP Software GmbH, Fuggerstrasse 11, D-86150 Augsburg
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-EGPL-3.1
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
@ -97,6 +104,7 @@ $(document).ready(function() {
|
||||
</style>
|
||||
[FINALCSSLINKS]
|
||||
[MODULEJAVASCRIPTHEAD]
|
||||
[JAVASCRIPTMODULES]
|
||||
[MODULESTYLESHEET]
|
||||
</head>
|
||||
<body class="[LAYOUTFIXMARKERCLASS]" data-module="[MODULE]" data-action="[ACTION]" data-version="[REVISION]">
|
||||
|
Loading…
Reference in New Issue
Block a user