diff --git a/Admin/Install/Navigation.install.json b/Admin/Install/Navigation.install.json index 2a58365..5d9fa7a 100755 --- a/Admin/Install/Navigation.install.json +++ b/Admin/Install/Navigation.install.json @@ -51,7 +51,22 @@ "uri": "{/base}/warehouse/stock/location/list", "target": "self", "icon": null, - "order": 1, + "order": 5, + "from": "WarehouseManagement", + "permission": { "permission": 2, "category": null, "element": null }, + "parent": 1001302001, + "children": [] + }, + { + "id": 1001303003, + "pid": "/warehouse/stock", + "type": 3, + "subtype": 1, + "name": "Types", + "uri": "{/base}/warehouse/stock/type/list", + "target": "self", + "icon": null, + "order": 10, "from": "WarehouseManagement", "permission": { "permission": 2, "category": null, "element": null }, "parent": 1001302001, diff --git a/Admin/Install/db.json b/Admin/Install/db.json index 780c3a7..128e43d 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -63,7 +63,8 @@ "warehousemgmt_stock_address": { "name": "warehousemgmt_stock_address", "type": "INT", - "null": false, + "null": true, + "default": null, "foreignTable": "address", "foreignKey": "address_id" } @@ -86,6 +87,38 @@ } } }, + "warehousemgmt_stock_type_l11n": { + "name": "warehousemgmt_stock_type_l11n", + "fields": { + "warehousemgmt_stock_type_l11n_id": { + "name": "warehousemgmt_stock_type_l11n_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "warehousemgmt_stock_type_l11n_name": { + "name": "warehousemgmt_stock_type_l11n_name", + "type": "VARCHAR(255)", + "null": false + }, + "warehousemgmt_stock_type_l11n_type": { + "name": "warehousemgmt_stock_type_l11n_type", + "type": "INT", + "null": false, + "foreignTable": "warehousemgmt_stock_type", + "foreignKey": "warehousemgmt_stock_type_id" + }, + "warehousemgmt_stock_type_l11n_language": { + "name": "warehousemgmt_stock_type_l11n_language", + "type": "VARCHAR(2)", + "default": null, + "null": true, + "foreignTable": "language", + "foreignKey": "language_639_1" + } + } + }, "warehousemgmt_stocklocation": { "name": "warehousemgmt_stocklocation", "fields": { @@ -112,7 +145,7 @@ "name": "warehousemgmt_stocklocation_type", "type": "INT", "null": true, - "default": "null", + "default": null, "foreignTable": "warehousemgmt_stock_type", "foreignKey": "warehousemgmt_stock_type_id" }, @@ -160,7 +193,7 @@ "name": "warehousemgmt_stockshelf_type", "type": "INT", "null": true, - "default": "null", + "default": null, "foreignTable": "warehousemgmt_stock_type", "foreignKey": "warehousemgmt_stock_type_id" }, @@ -184,6 +217,7 @@ }, "warehousemgmt_lot": { "name": "warehousemgmt_lot", + "todo": "consider to also allow notes (similar to media relation below)", "fields": { "warehousemgmt_lot_id": { "name": "warehousemgmt_lot_id", @@ -200,14 +234,16 @@ "foreignKey": "itemmgmt_item_id" }, "warehousemgmt_lot_purchase_price": { + "description": "only used if custom value, otherwise transaction protocol more accurate because of mixed prices and then lifo/fifo etc. depending on internal guidelines", "name": "warehousemgmt_lot_purchase_price", - "type": "INT", + "type": "BIGINT", "null": false }, "warehousemgmt_lot_internal": { "name": "warehousemgmt_lot_internal", "type": "VARCHAR(255)", - "null": false + "null": false, + "unique": true }, "warehousemgmt_lot_external": { "name": "warehousemgmt_lot_external", @@ -220,6 +256,18 @@ "type": "TINYINT", "null": false }, + "warehousemgmt_lot_manufactured": { + "name": "warehousemgmt_lot_manufactured", + "type": "DATETIME", + "null": true, + "default": null + }, + "warehousemgmt_lot_bestuse": { + "name": "warehousemgmt_lot_bestuse", + "type": "DATETIME", + "null": true, + "default": null + }, "warehousemgmt_lot_expiration": { "name": "warehousemgmt_lot_expiration", "type": "DATETIME", @@ -228,6 +276,235 @@ } } }, + "warehousemgmt_attr_type": { + "name": "warehousemgmt_attr_type", + "fields": { + "warehousemgmt_attr_type_id": { + "name": "warehousemgmt_attr_type_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "warehousemgmt_attr_type_name": { + "name": "warehousemgmt_attr_type_name", + "type": "VARCHAR(255)", + "null": false, + "unique": true + }, + "warehousemgmt_attr_type_datatype": { + "name": "warehousemgmt_attr_type_datatype", + "type": "INT(11)", + "null": false + }, + "warehousemgmt_attr_type_fields": { + "name": "warehousemgmt_attr_type_fields", + "type": "INT(11)", + "null": false + }, + "warehousemgmt_attr_type_custom": { + "name": "warehousemgmt_attr_type_custom", + "type": "TINYINT(1)", + "null": false + }, + "warehousemgmt_attr_type_required": { + "description": "Every item must have this attribute type if set to true.", + "name": "warehousemgmt_attr_type_required", + "type": "TINYINT(1)", + "null": false + }, + "warehousemgmt_attr_type_pattern": { + "description": "This is a regex validation pattern.", + "name": "warehousemgmt_attr_type_pattern", + "type": "VARCHAR(255)", + "null": false + } + } + }, + "warehousemgmt_attr_type_l11n": { + "name": "warehousemgmt_attr_type_l11n", + "fields": { + "warehousemgmt_attr_type_l11n_id": { + "name": "warehousemgmt_attr_type_l11n_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "warehousemgmt_attr_type_l11n_title": { + "name": "warehousemgmt_attr_type_l11n_title", + "type": "VARCHAR(255)", + "null": false + }, + "warehousemgmt_attr_type_l11n_type": { + "name": "warehousemgmt_attr_type_l11n_type", + "type": "INT(11)", + "null": false, + "foreignTable": "warehousemgmt_attr_type", + "foreignKey": "warehousemgmt_attr_type_id" + }, + "warehousemgmt_attr_type_l11n_lang": { + "name": "warehousemgmt_attr_type_l11n_lang", + "type": "VARCHAR(2)", + "null": false, + "foreignTable": "language", + "foreignKey": "language_639_1" + } + } + }, + "warehousemgmt_attr_value": { + "name": "warehousemgmt_attr_value", + "fields": { + "warehousemgmt_attr_value_id": { + "name": "warehousemgmt_attr_value_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "warehousemgmt_attr_value_default": { + "name": "warehousemgmt_attr_value_default", + "type": "TINYINT(1)", + "null": false + }, + "warehousemgmt_attr_value_valueStr": { + "name": "warehousemgmt_attr_value_valueStr", + "type": "VARCHAR(255)", + "null": true, + "default": null + }, + "warehousemgmt_attr_value_valueInt": { + "name": "warehousemgmt_attr_value_valueInt", + "type": "INT(11)", + "null": true, + "default": null + }, + "warehousemgmt_attr_value_valueDec": { + "name": "warehousemgmt_attr_value_valueDec", + "type": "DECIMAL(19,5)", + "null": true, + "default": null + }, + "warehousemgmt_attr_value_valueDat": { + "name": "warehousemgmt_attr_value_valueDat", + "type": "DATETIME", + "null": true, + "default": null + }, + "warehousemgmt_attr_value_unit": { + "name": "warehousemgmt_attr_value_unit", + "type": "VARCHAR(255)", + "null": false + }, + "warehousemgmt_attr_value_deptype": { + "name": "warehousemgmt_attr_value_deptype", + "type": "INT(11)", + "null": true, + "default": null, + "foreignTable": "warehousemgmt_attr_type", + "foreignKey": "warehousemgmt_attr_type_id" + }, + "warehousemgmt_attr_value_depvalue": { + "name": "warehousemgmt_attr_value_depvalue", + "type": "INT(11)", + "null": true, + "default": null, + "foreignTable": "warehousemgmt_attr_value", + "foreignKey": "warehousemgmt_attr_value_id" + } + } + }, + "warehousemgmt_attr_value_l11n": { + "name": "warehousemgmt_attr_value_l11n", + "fields": { + "warehousemgmt_attr_value_l11n_id": { + "name": "warehousemgmt_attr_value_l11n_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "warehousemgmt_attr_value_l11n_title": { + "name": "warehousemgmt_attr_value_l11n_title", + "type": "VARCHAR(255)", + "null": false + }, + "warehousemgmt_attr_value_l11n_value": { + "name": "warehousemgmt_attr_value_l11n_value", + "type": "INT(11)", + "null": false, + "foreignTable": "warehousemgmt_attr_value", + "foreignKey": "warehousemgmt_attr_value_id" + }, + "warehousemgmt_attr_value_l11n_lang": { + "name": "warehousemgmt_attr_value_l11n_lang", + "type": "VARCHAR(2)", + "null": false, + "foreignTable": "language", + "foreignKey": "language_639_1" + } + } + }, + "warehousemgmt_lot_attr_default": { + "name": "warehousemgmt_lot_attr_default", + "fields": { + "warehousemgmt_lot_attr_default_id": { + "name": "warehousemgmt_lot_attr_default_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "warehousemgmt_lot_attr_default_type": { + "name": "warehousemgmt_lot_attr_default_type", + "type": "INT(11)", + "null": false, + "foreignTable": "warehousemgmt_attr_type", + "foreignKey": "warehousemgmt_attr_type_id" + }, + "warehousemgmt_lot_attr_default_value": { + "name": "warehousemgmt_lot_attr_default_value", + "type": "INT(11)", + "null": false, + "foreignTable": "warehousemgmt_attr_value", + "foreignKey": "warehousemgmt_attr_value_id" + } + } + }, + "warehousemgmt_lot_attr": { + "name": "warehousemgmt_lot_attr", + "fields": { + "warehousemgmt_lot_attr_id": { + "name": "warehousemgmt_lot_attr_id", + "type": "INT", + "null": false, + "primary": true, + "autoincrement": true + }, + "warehousemgmt_lot_attr_lot": { + "name": "warehousemgmt_lot_attr_lot", + "type": "INT(11)", + "null": false, + "foreignTable": "warehousemgmt_lot", + "foreignKey": "warehousemgmt_lot_id" + }, + "warehousemgmt_lot_attr_type": { + "name": "warehousemgmt_lot_attr_type", + "type": "INT(11)", + "null": false, + "foreignTable": "warehousemgmt_attr_type", + "foreignKey": "warehousemgmt_attr_type_id" + }, + "warehousemgmt_lot_attr_value": { + "name": "warehousemgmt_lot_attr_value", + "type": "INT(11)", + "null": true, + "default": null, + "foreignTable": "warehousemgmt_attr_value", + "foreignKey": "warehousemgmt_attr_value_id" + } + } + }, "warehousemgmt_lot_media": { "name": "warehousemgmt_lot_media", "fields": { @@ -254,196 +531,188 @@ } } }, - "warehousemgmt_lot_status": { - "name": "warehousemgmt_lot_status", + "warehousemgmt_stock_distribution": { + "name": "warehousemgmt_stock_distribution", "fields": { - "warehousemgmt_lot_status_id": { - "name": "warehousemgmt_lot_status_id", + "warehousemgmt_stock_distribution_id": { + "name": "warehousemgmt_stock_distribution_id", "type": "INT", "null": false, "primary": true, "autoincrement": true }, - "warehousemgmt_lot_status_name": { - "name": "warehousemgmt_lot_status_name", - "type": "VARCHAR(255)", + "warehousemgmt_stock_distribution_item": { + "name": "warehousemgmt_stock_distribution_item", + "type": "INT", + "null": false, + "foreignTable": "itemmgmt_item", + "foreignKey": "itemmgmt_item_id" + }, + "warehousemgmt_stock_distribution_lot": { + "name": "warehousemgmt_stock_distribution_lot", + "type": "INT", + "null": false, + "foreignTable": "warehousemgmt_lot", + "foreignKey": "warehousemgmt_lot_id" + }, + "warehousemgmt_stock_distribution_shelf": { + "name": "warehousemgmt_stock_distribution_shelf", + "type": "INT", + "null": false, + "foreignTable": "warehousemgmt_stockshelf", + "foreignKey": "warehousemgmt_stockshelf_id" + }, + "warehousemgmt_stock_distribution_stocktype": { + "name": "warehousemgmt_stock_distribution_stocktype", + "type": "INT", + "null": false, + "foreignTable": "warehousemgmt_stock_type", + "foreignKey": "warehousemgmt_stock_type_id" + }, + "warehousemgmt_stock_distribution_quantity": { + "name": "warehousemgmt_stock_distribution_quantity", + "type": "BIGINT", "null": false } } }, - "warehousemgmt_lot_status_lot": { - "name": "warehousemgmt_lot_status_lot", + "warehousemgmt_stock_distribution_history": { + "name": "warehousemgmt_stock_distribution_history", "fields": { - "warehousemgmt_lot_status_lot_id": { - "name": "warehousemgmt_lot_status_lot_id", + "warehousemgmt_stock_distribution_history_id": { + "name": "warehousemgmt_stock_distribution_history_id", "type": "INT", "null": false, "primary": true, "autoincrement": true }, - "warehousemgmt_lot_status_lot_lot": { - "name": "warehousemgmt_lot_status_lot_lot", - "type": "VARCHAR(255)", - "null": false - }, - "warehousemgmt_lot_status_lot_status": { - "name": "warehousemgmt_lot_status_lot_status", + "warehousemgmt_stock_distribution_history_item": { + "name": "warehousemgmt_stock_distribution_history_item", "type": "INT", "null": false, - "foreignTable": "warehousemgmt_lot_status", - "foreignKey": "warehousemgmt_lot_status_id" + "foreignTable": "itemmgmt_item", + "foreignKey": "itemmgmt_item_id" }, - "warehousemgmt_lot_status_lot_comment": { - "name": "warehousemgmt_lot_status_lot_comment", - "type": "VARCHAR(255)", + "warehousemgmt_stock_distribution_history_lot": { + "name": "warehousemgmt_stock_distribution_history_lot", + "type": "INT", + "null": false, + "foreignTable": "warehousemgmt_lot", + "foreignKey": "warehousemgmt_lot_id" + }, + "warehousemgmt_stock_distribution_history_shelf": { + "name": "warehousemgmt_stock_distribution_history_shelf", + "type": "INT", + "null": false, + "foreignTable": "warehousemgmt_stockshelf", + "foreignKey": "warehousemgmt_stockshelf_id" + }, + "warehousemgmt_stock_distribution_history_stocktype": { + "name": "warehousemgmt_stock_distribution_history_stocktype", + "type": "INT", + "null": false, + "foreignTable": "warehousemgmt_stock_type", + "foreignKey": "warehousemgmt_stock_type_id" + }, + "warehousemgmt_stock_distribution_history_quantity": { + "name": "warehousemgmt_stock_distribution_history_quantity", + "type": "BIGINT", "null": false }, - "warehousemgmt_lot_status_lot_comment_raw": { - "name": "warehousemgmt_lot_status_lot_comment_raw", - "type": "VARCHAR(255)", - "null": false - }, - "warehousemgmt_lot_status_lot_created_by": { - "name": "warehousemgmt_lot_status_lot_created_by", - "type": "VARCHAR(255)", - "null": false - }, - "warehousemgmt_lot_status_lot_created_at": { - "name": "warehousemgmt_lot_status_lot_created_at", + "warehousemgmt_stock_distribution_history_datetime": { + "name": "warehousemgmt_stock_distribution_history_datetime", "type": "DATETIME", "null": false } } }, - "warehousemgmt_movement_subtype": { - "name": "warehousemgmt_movement_subtype", + "warehousemgmt_stock_transaction": { + "name": "warehousemgmt_stock_transaction", "fields": { - "warehousemgmt_movement_subtype_id": { - "name": "warehousemgmt_movement_subtype_id", + "warehousemgmt_stock_transaction_id": { + "name": "warehousemgmt_stock_transaction_id", "type": "INT", "null": false, "primary": true, "autoincrement": true }, - "warehousemgmt_movement_subtype_name": { - "name": "warehousemgmt_movement_subtype_name", - "type": "VARCHAR(255)", + "warehousemgmt_stock_transaction_state": { + "description": "Is draft (= reserved = bill currently in draft) or finalized", + "name": "warehousemgmt_stock_transaction_state", + "type": "TINYINT", "null": false }, - "warehousemgmt_movement_subtype_type": { - "name": "warehousemgmt_movement_subtype_type", + "warehousemgmt_stock_transaction_quantity": { + "name": "warehousemgmt_stock_transaction_quantity", + "type": "BIGINT", + "null": false + }, + "warehousemgmt_stock_transaction_pprice": { + "name": "warehousemgmt_stock_transaction_pprice", + "type": "BIGINT", + "null": false + }, + "warehousemgmt_stock_transaction_type": { + "name": "warehousemgmt_stock_transaction_type", "type": "INT", "null": false - } - } - }, - "warehousemgmt_movement": { - "name": "warehousemgmt_movement", - "fields": { - "warehousemgmt_movement_id": { - "name": "warehousemgmt_movement_id", + }, + "warehousemgmt_stock_transaction_item": { + "name": "warehousemgmt_stock_transaction_item", "type": "INT", "null": false, - "primary": true, - "autoincrement": true + "foreignTable": "itemmgmt_item", + "foreignKey": "itemmgmt_item_id" }, - "warehousemgmt_movement_quantity": { - "name": "warehousemgmt_movement_quantity", + "warehousemgmt_stock_transaction_from_lot": { + "name": "warehousemgmt_stock_transaction_from_lot", "type": "INT", - "null": false - }, - "warehousemgmt_movement_lot": { - "name": "warehousemgmt_movement_lot", - "type": "INT", - "null": true, - "default": null, + "null": false, "foreignTable": "warehousemgmt_lot", "foreignKey": "warehousemgmt_lot_id" }, - "warehousemgmt_movement_from": { - "name": "warehousemgmt_movement_from", - "type": "INT", - "null": true, - "default": null, - "foreignTable": "warehousemgmt_stocklocation", - "foreignKey": "warehousemgmt_stocklocation_id" - }, - "warehousemgmt_movement_to": { - "name": "warehousemgmt_movement_to", - "type": "INT", - "null": true, - "default": null, - "foreignTable": "warehousemgmt_stocklocation", - "foreignKey": "warehousemgmt_stocklocation_id" - }, - "warehousemgmt_movement_type": { - "name": "warehousemgmt_movement_type", - "type": "INT", - "null": false - }, - "warehousemgmt_movement_subtype": { - "description": "Destroy, return, sale, purchase, ...", - "name": "warehousemgmt_movement_subtype", + "warehousemgmt_stock_transaction_from_shelf": { + "name": "warehousemgmt_stock_transaction_from_shelf", "type": "INT", "null": false, - "foreignTable": "warehousemgmt_movement_subtype", - "foreignKey": "warehousemgmt_movement_subtype_id" + "foreignTable": "warehousemgmt_stockshelf", + "foreignKey": "warehousemgmt_stockshelf_id" }, - "warehousemgmt_movement_reference": { - "name": "warehousemgmt_movement_reference", - "type": "VARCHAR(255)", - "null": false + "warehousemgmt_stock_transaction_from_stocktype": { + "name": "warehousemgmt_stock_transaction_from_stocktype", + "type": "INT", + "null": false, + "foreignTable": "warehousemgmt_stock_type", + "foreignKey": "warehousemgmt_stock_type_id" }, - "warehousemgmt_movement_bill_element": { - "name": "warehousemgmt_movement_bill_element", + "warehousemgmt_stock_transaction_to_lot": { + "name": "warehousemgmt_stock_transaction_to_lot", + "type": "INT", + "null": false, + "foreignTable": "warehousemgmt_lot", + "foreignKey": "warehousemgmt_lot_id" + }, + "warehousemgmt_stock_transaction_to_shelf": { + "name": "warehousemgmt_stock_transaction_to_shelf", + "type": "INT", + "null": false, + "foreignTable": "warehousemgmt_stockshelf", + "foreignKey": "warehousemgmt_stockshelf_id" + }, + "warehousemgmt_stock_transaction_to_stocktype": { + "name": "warehousemgmt_stock_transaction_to_stocktype", + "type": "INT", + "null": false, + "foreignTable": "warehousemgmt_stock_type", + "foreignKey": "warehousemgmt_stock_type_id" + }, + "warehousemgmt_stock_transaction_bill_element": { + "description": "indirectly contains createdat/by in the bill as well as supplier/customer", + "name": "warehousemgmt_stock_transaction_bill_element", "type": "INT", "null": false, "foreignTable": "billing_bill_element", "foreignKey": "billing_bill_element_id" - }, - "warehousemgmt_movement_created_by": { - "name": "warehousemgmt_movement_created_by", - "type": "INT", - "null": false, - "foreignTable": "account", - "foreignKey": "account_id" - }, - "warehousemgmt_movement_created_at": { - "name": "warehousemgmt_movement_created_at", - "type": "DATETIME", - "null": false - } - } - }, - "warehousemgmt_lot_quantity": { - "name": "warehousemgmt_lot_quantity", - "description": "Stores the quantity per lot per stocklocation. For every? (maybe only for transfers?) stock movement there are 2 item stock entries (from/to) where the last element per item (see movement_item) shows the current stock per lot and location. Consider to create even one more un-normalized table which shows quantity per item per stock for faster results?", - "fields": { - "warehousemgmt_lot_quantity_id": { - "name": "warehousemgmt_lot_quantity_id", - "type": "INT", - "null": false, - "primary": true, - "autoincrement": true - }, - "warehousemgmt_lot_quantity_quantity": { - "name": "warehousemgmt_lot_quantity_quantity", - "type": "INT", - "null": false - }, - "warehousemgmt_lot_quantity_stocklocation": { - "name": "warehousemgmt_lot_quantity_stocklocation", - "type": "INT", - "null": false, - "foreignTable": "warehousemgmt_stocklocation", - "foreignKey": "warehousemgmt_stocklocation_id" - }, - "warehousemgmt_lot_quantity_movement": { - "name": "warehousemgmt_lot_quantity_movement", - "type": "INT", - "null": false, - "foreignTable": "warehousemgmt_movement", - "foreignKey": "warehousemgmt_movement_id" } } } diff --git a/Admin/Install/types.json b/Admin/Install/types.json new file mode 100644 index 0000000..4f1da66 --- /dev/null +++ b/Admin/Install/types.json @@ -0,0 +1,51 @@ +[ + { + "name": "default", + "l11n": { + "en": "Default", + "de": "Standard" + } + }, + { + "name": "incoming", + "l11n": { + "en": "Incoming", + "de": "Wareneingang" + } + }, + { + "name": "outgoing", + "l11n": { + "en": "Outgoing", + "de": "Warenausgang" + } + }, + { + "name": "return", + "l11n": { + "en": "Return", + "de": "Rückgabe" + } + }, + { + "name": "quarantine", + "l11n": { + "en": "Quarantine", + "de": "Quarantäne" + } + }, + { + "name": "quality_control", + "l11n": { + "en": "Quality control", + "de": "Qualitätskontrolle" + } + }, + { + "name": "retention_sample", + "l11n": { + "en": "Retention sample", + "de": "Rückstellmuster" + } + } +] \ No newline at end of file diff --git a/Admin/Installer.php b/Admin/Installer.php index e70c99c..1960427 100755 --- a/Admin/Installer.php +++ b/Admin/Installer.php @@ -20,8 +20,11 @@ use Modules\WarehouseManagement\Models\StockLocationMapper; use Modules\WarehouseManagement\Models\StockMapper; use phpOMS\Application\ApplicationAbstract; use phpOMS\Config\SettingsInterface; +use phpOMS\Message\Http\HttpRequest; +use phpOMS\Message\Http\HttpResponse; use phpOMS\Module\InstallerAbstract; use phpOMS\Module\ModuleInfo; +use phpOMS\Uri\HttpUri; /** * Installer class. @@ -49,6 +52,20 @@ final class Installer extends InstallerAbstract parent::install($app, $info, $cfgHandler); self::createDefaultStock(); + + /* Stock types */ + $fileContent = \file_get_contents(__DIR__ . '/Install/types.json'); + if ($fileContent === false) { + return; + } + + /** @var array $types */ + $types = \json_decode($fileContent, true); + if ($types === false) { + return; + } + + self::createStockTypes($app, $types); } /** @@ -61,11 +78,75 @@ final class Installer extends InstallerAbstract private static function createDefaultStock() : void { $stock = new Stock('Default'); - $stock->type = 0; + $stock->unit = 1; StockMapper::create()->execute($stock); $stockLocation = new StockLocation((string) ($stock->id . '-1')); $stockLocation->stock = $stock; StockLocationMapper::create()->execute($stockLocation); } + + /** + * Install default stock types + * + * @param ApplicationAbstract $app Application + * @param array $types Stock types + * + * @return array + * + * @since 1.0.0 + */ + private static function createStockTypes(ApplicationAbstract $app, array $types) : array + { + $stockTypes = []; + + /** @var \Modules\WarehouseManagement\Controller\ApiStockTypeController $module */ + $module = $app->moduleManager->getModuleInstance('WarehouseManagement', 'ApiStockType'); + + // @todo: allow multiple alternative stock templates + // @todo: implement ordering of templates + + foreach ($types as $type) { + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('name', $type['name'] ?? ''); + $request->setData('title', \reset($type['l11n'])); + $request->setData('language', \array_keys($type['l11n'])[0] ?? 'en'); + + $module->apiStockTypeCreate($request, $response); + + $responseData = $response->get(''); + if (!\is_array($responseData)) { + continue; + } + + $stockType = !\is_array($responseData['response']) + ? $responseData['response']->toArray() + : $responseData['response']; + + $stockTypes[] = $stockType; + + $isFirst = true; + foreach ($type['l11n'] as $language => $l11n) { + if ($isFirst) { + $isFirst = false; + continue; + } + + $response = new HttpResponse(); + $request = new HttpRequest(new HttpUri('')); + + $request->header->account = 1; + $request->setData('title', $l11n); + $request->setData('language', $language); + $request->setData('type', $stockType['id']); + + $module->apiStockTypeL11nCreate($request, $response); + } + } + + return $stockTypes; + } } diff --git a/Admin/Routes/Web/Backend.php b/Admin/Routes/Web/Backend.php index 726cb18..a9cff5b 100755 --- a/Admin/Routes/Web/Backend.php +++ b/Admin/Routes/Web/Backend.php @@ -40,6 +40,28 @@ return [ ], ], ], + '^.*/warehouse/stock/type/list.*$' => [ + [ + 'dest' => '\Modules\WarehouseManagement\Controller\BackendController:viewStockTypeList', + 'verb' => RouteVerb::GET, + 'permission' => [ + 'module' => BackendController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::STOCK, + ], + ], + ], + '^.*/warehouse/stock/type(\?.*)?$' => [ + [ + 'dest' => '\Modules\WarehouseManagement\Controller\BackendController:viewStockType', + 'verb' => RouteVerb::GET, + 'permission' => [ + 'module' => BackendController::NAME, + 'type' => PermissionType::READ, + 'state' => PermissionCategory::STOCK, + ], + ], + ], '^.*/warehouse/stock/location/list.*$' => [ [ 'dest' => '\Modules\WarehouseManagement\Controller\BackendController:viewStockLocationList', diff --git a/Controller/ApiAttributeController.php b/Controller/ApiAttributeController.php new file mode 100644 index 0000000..0768e7b --- /dev/null +++ b/Controller/ApiAttributeController.php @@ -0,0 +1,417 @@ +validateLotAttributeCreate($request))) { + $response->data['attribute_create'] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + $attribute = $this->createLotAttributeFromRequest($request); + $this->createModel($request->header->account, $attribute, LotAttributeMapper::class, 'attribute', $request->getOrigin()); + + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Attribute', 'Attribute successfully created', $attribute); + } + + /** + * Method to create item attribute from request. + * + * @param RequestAbstract $request Request + * + * @return Attribute + * + * @since 1.0.0 + */ + private function createLotAttributeFromRequest(RequestAbstract $request) : Attribute + { + $attribute = new Attribute(); + $attribute->ref = (int) $request->getData('ref'); + $attribute->type = new NullAttributeType((int) $request->getData('type')); + + if ($request->hasData('value')) { + $attribute->value = new NullAttributeValue((int) $request->getData('value')); + } else { + $newRequest = clone $request; + $newRequest->setData('value', $request->getData('custom'), true); + + $value = $this->createLotAttributeValueFromRequest($newRequest); + + $attribute->value = $value; + } + + return $attribute; + } + + /** + * Validate lot attribute create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateLotAttributeCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['type'] = !$request->hasData('type')) + || ($val['value'] = (!$request->hasData('value') && !$request->hasData('custom'))) + || ($val['lot'] = !$request->hasData('lot')) + ) { + return $val; + } + + return []; + } + + /** + * Api method to create lot attribute l11n + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiLotAttributeTypeL11nCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + if (!empty($val = $this->validateLotAttributeTypeL11nCreate($request))) { + $response->data['attr_type_l11n_create'] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + $attrL11n = $this->createLotAttributeTypeL11nFromRequest($request); + $this->createModel($request->header->account, $attrL11n, LotAttributeTypeL11nMapper::class, 'attr_type_l11n', $request->getOrigin()); + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Localization', 'Localization successfully created', $attrL11n); + } + + /** + * Method to create lot attribute l11n from request. + * + * @param RequestAbstract $request Request + * + * @return BaseStringL11n + * + * @since 1.0.0 + */ + private function createLotAttributeTypeL11nFromRequest(RequestAbstract $request) : BaseStringL11n + { + $attrL11n = new BaseStringL11n(); + $attrL11n->ref = $request->getDataInt('type') ?? 0; + $attrL11n->setLanguage( + $request->getDataString('language') ?? $request->header->l11n->language + ); + $attrL11n->content = $request->getDataString('title') ?? ''; + + return $attrL11n; + } + + /** + * Validate lot attribute l11n create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateLotAttributeTypeL11nCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['title'] = !$request->hasData('title')) + || ($val['type'] = !$request->hasData('type')) + ) { + return $val; + } + + return []; + } + + /** + * Api method to create lot attribute type + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiLotAttributeTypeCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + if (!empty($val = $this->validateLotAttributeTypeCreate($request))) { + $response->data['attr_type_create'] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + $attrType = $this->createLotAttributeTypeFromRequest($request); + $this->createModel($request->header->account, $attrType, LotAttributeTypeMapper::class, 'attr_type', $request->getOrigin()); + + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Attribute type', 'Attribute type successfully created', $attrType); + } + + /** + * Method to create lot attribute from request. + * + * @param RequestAbstract $request Request + * + * @return AttributeType + * + * @since 1.0.0 + */ + private function createLotAttributeTypeFromRequest(RequestAbstract $request) : AttributeType + { + $attrType = new AttributeType($request->getDataString('name') ?? ''); + $attrType->datatype = $request->getDataInt('datatype') ?? 0; + $attrType->custom = $request->getDataBool('custom') ?? false; + $attrType->isRequired = (bool) ($request->getData('is_required') ?? false); + $attrType->validationPattern = $request->getDataString('validation_pattern') ?? ''; + $attrType->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN); + $attrType->setFields($request->getDataInt('fields') ?? 0); + + return $attrType; + } + + /** + * Validate lot attribute create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateLotAttributeTypeCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['title'] = !$request->hasData('title')) + || ($val['name'] = !$request->hasData('name')) + ) { + return $val; + } + + return []; + } + + /** + * Api method to create lot attribute value + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiLotAttributeValueCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + if (!empty($val = $this->validateLotAttributeValueCreate($request))) { + $response->data['attr_value_create'] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + $attrValue = $this->createLotAttributeValueFromRequest($request); + $this->createModel($request->header->account, $attrValue, LotAttributeValueMapper::class, 'attr_value', $request->getOrigin()); + + if ($attrValue->isDefault) { + $this->createModelRelation( + $request->header->account, + (int) $request->getData('type'), + $attrValue->id, + LotAttributeTypeMapper::class, 'defaults', '', $request->getOrigin() + ); + } + + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Attribute value', 'Attribute value successfully created', $attrValue); + } + + /** + * Method to create lot attribute value from request. + * + * @param RequestAbstract $request Request + * + * @return AttributeValue + * + * @since 1.0.0 + */ + private function createLotAttributeValueFromRequest(RequestAbstract $request) : AttributeValue + { + /** @var \Modules\Attribute\Models\AttributeType $type */ + $type = LotAttributeTypeMapper::get() + ->where('id', $request->getDataInt('type') ?? 0) + ->execute(); + + $attrValue = new AttributeValue(); + $attrValue->isDefault = $request->getDataBool('default') ?? false; + $attrValue->setValue($request->getDataString('value'), $type->datatype); + + if ($request->hasData('title')) { + $attrValue->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN); + } + + return $attrValue; + } + + /** + * Validate lot attribute value create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateLotAttributeValueCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['type'] = !$request->hasData('type')) + || ($val['value'] = !$request->hasData('value')) + ) { + return $val; + } + + return []; + } + + /** + * Api method to create lot attribute l11n + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiLotAttributeValueL11nCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + if (!empty($val = $this->validateLotAttributeValueL11nCreate($request))) { + $response->data['attr_value_l11n_create'] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + $attrL11n = $this->createLotAttributeValueL11nFromRequest($request); + $this->createModel($request->header->account, $attrL11n, LotAttributeValueL11nMapper::class, 'attr_value_l11n', $request->getOrigin()); + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Localization', 'Localization successfully created', $attrL11n); + } + + /** + * Method to create lot attribute l11n from request. + * + * @param RequestAbstract $request Request + * + * @return BaseStringL11n + * + * @since 1.0.0 + */ + private function createLotAttributeValueL11nFromRequest(RequestAbstract $request) : BaseStringL11n + { + $attrL11n = new BaseStringL11n(); + $attrL11n->ref = $request->getDataInt('value') ?? 0; + $attrL11n->setLanguage( + $request->getDataString('language') ?? $request->header->l11n->language + ); + $attrL11n->content = $request->getDataString('title') ?? ''; + + return $attrL11n; + } + + /** + * Validate lot attribute l11n create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateLotAttributeValueL11nCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['title'] = !$request->hasData('title')) + || ($val['value'] = !$request->hasData('value')) + ) { + return $val; + } + + return []; + } +} diff --git a/Controller/ApiController.php b/Controller/ApiController.php index db51bda..4044727 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -14,6 +14,7 @@ declare(strict_types=1); namespace Modules\WarehouseManagement\Controller; +use Modules\Billing\Models\Bill; use Modules\WarehouseManagement\Models\Stock; use Modules\WarehouseManagement\Models\StockLocation; use Modules\WarehouseManagement\Models\StockLocationMapper; @@ -37,7 +38,7 @@ final class ApiController extends Controller * @param int $account Account * @param mixed $old Old stock model * @param mixed $new New / created stock model - * @param int $type Event type (usually mapper hash) + * @param null|int $type Event type (usually mapper hash) * @param string $trigger Trigger name * @param null|string $module Module name who triggers the event * @param null|string $ref Reference (e.g. reference to a different model) @@ -52,7 +53,7 @@ final class ApiController extends Controller int $account, mixed $old, mixed $new, - int $type = 0, + int $type = null, string $trigger = '', string $module = null, string $ref = null, @@ -62,7 +63,6 @@ final class ApiController extends Controller { /** @var \Modules\ClientManagement\Models\Client|\Modules\SupplierManagement\Models\Supplier $new */ $stock = new Stock($new->number); - $stock->type = 1; StockMapper::create()->execute($stock); $stockLocation = new StockLocation($stock->name . '-1'); @@ -95,7 +95,7 @@ final class ApiController extends Controller int $account, mixed $old, mixed $new, - int $type = 0, + int $type = null, string $trigger = '', string $module = null, string $ref = null, @@ -125,4 +125,6 @@ final class ApiController extends Controller return; } } + + } diff --git a/Controller/ApiStockTypeController.php b/Controller/ApiStockTypeController.php new file mode 100644 index 0000000..87d4e29 --- /dev/null +++ b/Controller/ApiStockTypeController.php @@ -0,0 +1,175 @@ +validateStockTypeCreate($request))) { + $response->data['stock_type_create'] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + $stockType = $this->createStockTypeFromRequest($request); + $this->createModel($request->header->account, $stockType, StockTypeMapper::class, 'stock_type', $request->getOrigin()); + + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Stock type', 'Stock type successfully created', $stockType); + } + + /** + * Method to create item attribute from request. + * + * @param RequestAbstract $request Request + * + * @return StockType + * + * @since 1.0.0 + */ + private function createStockTypeFromRequest(RequestAbstract $request) : StockType + { + $stockType = new StockType(); + $stockType->name = $request->getDataString('name') ?? ''; + $stockType->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN); + + return $stockType; + } + + /** + * Validate item attribute create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateStockTypeCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['title'] = !$request->hasData('title')) + || ($val['name'] = !$request->hasData('name')) + ) { + return $val; + } + + return []; + } + + /** + * Api method to create item attribute l11n + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return void + * + * @api + * + * @since 1.0.0 + */ + public function apiStockTypeL11nCreate(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : void + { + if (!empty($val = $this->validateStockTypeL11nCreate($request))) { + $response->data['stock_type_l11n_create'] = new FormValidation($val); + $response->header->status = RequestStatusCode::R_400; + + return; + } + + $stockTypeL11n = $this->createStockTypeL11nFromRequest($request); + $this->createModel($request->header->account, $stockTypeL11n, StockTypeL11nMapper::class, 'stock_type_l11n', $request->getOrigin()); + $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Localization', 'Localization successfully created', $stockTypeL11n); + } + + /** + * Method to create item attribute l11n from request. + * + * @param RequestAbstract $request Request + * + * @return BaseStringL11n + * + * @since 1.0.0 + */ + private function createStockTypeL11nFromRequest(RequestAbstract $request) : BaseStringL11n + { + $stockTypeL11n = new BaseStringL11n(); + $stockTypeL11n->ref = $request->getDataInt('type') ?? 0; + $stockTypeL11n->setLanguage( + $request->getDataString('language') ?? $request->header->l11n->language + ); + $stockTypeL11n->content = $request->getDataString('title') ?? ''; + + return $stockTypeL11n; + } + + /** + * Validate item attribute l11n create request + * + * @param RequestAbstract $request Request + * + * @return array + * + * @since 1.0.0 + */ + private function validateStockTypeL11nCreate(RequestAbstract $request) : array + { + $val = []; + if (($val['title'] = !$request->hasData('title')) + || ($val['type'] = !$request->hasData('type')) + ) { + return $val; + } + + return []; + } +} diff --git a/Controller/BackendController.php b/Controller/BackendController.php index 637d4d3..587a048 100755 --- a/Controller/BackendController.php +++ b/Controller/BackendController.php @@ -16,6 +16,8 @@ namespace Modules\WarehouseManagement\Controller; use Modules\WarehouseManagement\Models\StockLocationMapper; use Modules\WarehouseManagement\Models\StockMapper; +use Modules\WarehouseManagement\Models\StockTypeL11nMapper; +use Modules\WarehouseManagement\Models\StockTypeMapper; use phpOMS\Contract\RenderableInterface; use phpOMS\Message\RequestAbstract; use phpOMS\Message\ResponseAbstract; @@ -32,6 +34,48 @@ use phpOMS\Views\View; */ final class BackendController extends Controller { + /** + * Routing end-point for application behaviour. + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return RenderableInterface Returns a renderable object + * + * @since 1.0.0 + * @codeCoverageIgnore + */ + public function viewStockTypeList(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + + $view->setTemplate('/Modules/WarehouseManagement/Theme/Backend/stock-type-list'); + $view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1001302001, $request, $response); + + if ($request->getData('ptype') === 'p') { + $view->data['types'] = StockTypeMapper::getAll() + ->with('l11n') + ->where('l11n/language', $response->header->l11n->language) + ->limit(25) + ->execute(); + } elseif ($request->getData('ptype') === 'n') { + $view->data['types'] = StockTypeMapper::getAll() + ->with('l11n') + ->where('l11n/language', $response->header->l11n->language) + ->limit(25) + ->execute(); + } else { + $view->data['types'] = StockTypeMapper::getAll() + ->with('l11n') + ->where('l11n/language', $response->header->l11n->language) + ->limit(25) + ->execute(); + } + + return $view; + } + /** * Routing end-point for application behaviour. * @@ -53,17 +97,14 @@ final class BackendController extends Controller if ($request->getData('ptype') === 'p') { $view->data['stocks'] = StockMapper::getAll() - ->where('id', $request->getDataInt('id') ?? 0) ->limit(25) ->execute(); } elseif ($request->getData('ptype') === 'n') { $view->data['stocks'] = StockMapper::getAll() - ->where('id', $request->getDataInt('id') ?? 0) ->limit(25) ->execute(); } else { $view->data['stocks'] = StockMapper::getAll() - ->where('id', 0) ->limit(25) ->execute(); } @@ -95,6 +136,37 @@ final class BackendController extends Controller return $view; } + /** + * Routing end-point for application behaviour. + * + * @param RequestAbstract $request Request + * @param ResponseAbstract $response Response + * @param mixed $data Generic data + * + * @return RenderableInterface Returns a renderable object + * + * @since 1.0.0 + * @codeCoverageIgnore + */ + public function viewStockType(RequestAbstract $request, ResponseAbstract $response, mixed $data = null) : RenderableInterface + { + $view = new View($this->app->l11nManager, $request, $response); + + $view->setTemplate('/Modules/WarehouseManagement/Theme/Backend/stock-type-profile'); + $view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1001302001, $request, $response); + + $view->data['type'] = StockMapper::get()->where('id', (int) $request->getData('id'))->execute(); + + $l11nValues = StockTypeL11nMapper::getAll() + ->with('type') + ->where('ref', $view->data['type']->id) + ->execute(); + + $view->data['l11nValues'] = $l11nValues; + + return $view; + } + /** * Routing end-point for application behaviour. * @@ -116,19 +188,19 @@ final class BackendController extends Controller if ($request->getData('ptype') === 'p') { $view->data['locations'] = StockLocationMapper::getAll() - ->where('id', $request->getDataInt('id') ?? 0) - ->limit(25) - ->execute(); + ->with('stock') + ->limit(25) + ->execute(); } elseif ($request->getData('ptype') === 'n') { $view->data['locations'] = StockLocationMapper::getAll() - ->where('id', $request->getDataInt('id') ?? 0) - ->limit(25) - ->execute(); + ->with('stock') + ->limit(25) + ->execute(); } else { $view->data['locations'] = StockLocationMapper::getAll() - ->where('id', 0) - ->limit(25) - ->execute(); + ->with('stock') + ->limit(25) + ->execute(); } return $view; diff --git a/Models/Attribute/LotAttributeMapper.php b/Models/Attribute/LotAttributeMapper.php new file mode 100644 index 0000000..c65e3ec --- /dev/null +++ b/Models/Attribute/LotAttributeMapper.php @@ -0,0 +1,86 @@ + + */ +final class LotAttributeMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'warehousemgmt_lot_attr_id' => ['name' => 'warehousemgmt_lot_attr_id', 'type' => 'int', 'internal' => 'id'], + 'warehousemgmt_lot_attr_lot' => ['name' => 'warehousemgmt_lot_attr_lot', 'type' => 'int', 'internal' => 'ref'], + 'warehousemgmt_lot_attr_type' => ['name' => 'warehousemgmt_lot_attr_type', 'type' => 'int', 'internal' => 'type'], + 'warehousemgmt_lot_attr_value' => ['name' => 'warehousemgmt_lot_attr_value', 'type' => 'int', 'internal' => 'value'], + ]; + + /** + * Has one relation. + * + * @var array + * @since 1.0.0 + */ + public const OWNS_ONE = [ + 'type' => [ + 'mapper' => LotAttributeTypeMapper::class, + 'external' => 'warehousemgmt_lot_attr_type', + ], + 'value' => [ + 'mapper' => LotAttributeValueMapper::class, + 'external' => 'warehousemgmt_lot_attr_value', + ], + ]; + + /** + * Model to use by the mapper. + * + * @var class-string + * @since 1.0.0 + */ + public const MODEL = Attribute::class; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'warehousemgmt_lot_attr'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'warehousemgmt_lot_attr_id'; +} diff --git a/Models/Attribute/LotAttributeTypeL11nMapper.php b/Models/Attribute/LotAttributeTypeL11nMapper.php new file mode 100644 index 0000000..afa96cc --- /dev/null +++ b/Models/Attribute/LotAttributeTypeL11nMapper.php @@ -0,0 +1,69 @@ + + */ +final class LotAttributeTypeL11nMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'warehousemgmt_attr_type_l11n_id' => ['name' => 'warehousemgmt_attr_type_l11n_id', 'type' => 'int', 'internal' => 'id'], + 'warehousemgmt_attr_type_l11n_title' => ['name' => 'warehousemgmt_attr_type_l11n_title', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true], + 'warehousemgmt_attr_type_l11n_type' => ['name' => 'warehousemgmt_attr_type_l11n_type', 'type' => 'int', 'internal' => 'ref'], + 'warehousemgmt_attr_type_l11n_lang' => ['name' => 'warehousemgmt_attr_type_l11n_lang', 'type' => 'string', 'internal' => 'language'], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'warehousemgmt_attr_type_l11n'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'warehousemgmt_attr_type_l11n_id'; + + /** + * Model to use by the mapper. + * + * @var class-string + * @since 1.0.0 + */ + public const MODEL = BaseStringL11n::class; +} diff --git a/Models/Attribute/LotAttributeTypeMapper.php b/Models/Attribute/LotAttributeTypeMapper.php new file mode 100644 index 0000000..3d07f08 --- /dev/null +++ b/Models/Attribute/LotAttributeTypeMapper.php @@ -0,0 +1,94 @@ + + */ +final class LotAttributeTypeMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'warehousemgmt_attr_type_id' => ['name' => 'warehousemgmt_attr_type_id', 'type' => 'int', 'internal' => 'id'], + 'warehousemgmt_attr_type_name' => ['name' => 'warehousemgmt_attr_type_name', 'type' => 'string', 'internal' => 'name', 'autocomplete' => true], + 'warehousemgmt_attr_type_datatype' => ['name' => 'warehousemgmt_attr_type_datatype', 'type' => 'int', 'internal' => 'datatype'], + 'warehousemgmt_attr_type_fields' => ['name' => 'warehousemgmt_attr_type_fields', 'type' => 'int', 'internal' => 'fields'], + 'warehousemgmt_attr_type_custom' => ['name' => 'warehousemgmt_attr_type_custom', 'type' => 'bool', 'internal' => 'custom'], + 'warehousemgmt_attr_type_pattern' => ['name' => 'warehousemgmt_attr_type_pattern', 'type' => 'string', 'internal' => 'validationPattern'], + 'warehousemgmt_attr_type_required' => ['name' => 'warehousemgmt_attr_type_required', 'type' => 'bool', 'internal' => 'isRequired'], + ]; + + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + public const HAS_MANY = [ + 'l11n' => [ + 'mapper' => LotAttributeTypeL11nMapper::class, + 'table' => 'warehousemgmt_attr_type_l11n', + 'self' => 'warehousemgmt_attr_type_l11n_type', + 'column' => 'content', + 'external' => null, + ], + 'defaults' => [ + 'mapper' => LotAttributeValueMapper::class, + 'table' => 'warehousemgmt_lot_attr_default', + 'self' => 'warehousemgmt_lot_attr_default_type', + 'external' => 'warehousemgmt_lot_attr_default_value', + ], + ]; + + /** + * Model to use by the mapper. + * + * @var class-string + * @since 1.0.0 + */ + public const MODEL = AttributeType::class; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'warehousemgmt_attr_type'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'warehousemgmt_attr_type_id'; +} diff --git a/Models/Attribute/LotAttributeValueL11nMapper.php b/Models/Attribute/LotAttributeValueL11nMapper.php new file mode 100644 index 0000000..ed11ab2 --- /dev/null +++ b/Models/Attribute/LotAttributeValueL11nMapper.php @@ -0,0 +1,69 @@ + + */ +final class LotAttributeValueL11nMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'warehousemgmt_attr_value_l11n_id' => ['name' => 'warehousemgmt_attr_value_l11n_id', 'type' => 'int', 'internal' => 'id'], + 'warehousemgmt_attr_value_l11n_title' => ['name' => 'warehousemgmt_attr_value_l11n_title', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true], + 'warehousemgmt_attr_value_l11n_value' => ['name' => 'warehousemgmt_attr_value_l11n_value', 'type' => 'int', 'internal' => 'ref'], + 'warehousemgmt_attr_value_l11n_lang' => ['name' => 'warehousemgmt_attr_value_l11n_lang', 'type' => 'string', 'internal' => 'language'], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'warehousemgmt_attr_value_l11n'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'warehousemgmt_attr_value_l11n_id'; + + /** + * Model to use by the mapper. + * + * @var class-string + * @since 1.0.0 + */ + public const MODEL = BaseStringL11n::class; +} diff --git a/Models/Attribute/LotAttributeValueMapper.php b/Models/Attribute/LotAttributeValueMapper.php new file mode 100644 index 0000000..7f0e616 --- /dev/null +++ b/Models/Attribute/LotAttributeValueMapper.php @@ -0,0 +1,89 @@ + + */ +final class LotAttributeValueMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'warehousemgmt_attr_value_id' => ['name' => 'warehousemgmt_attr_value_id', 'type' => 'int', 'internal' => 'id'], + 'warehousemgmt_attr_value_default' => ['name' => 'warehousemgmt_attr_value_default', 'type' => 'bool', 'internal' => 'isDefault'], + 'warehousemgmt_attr_value_valueStr' => ['name' => 'warehousemgmt_attr_value_valueStr', 'type' => 'string', 'internal' => 'valueStr'], + 'warehousemgmt_attr_value_valueInt' => ['name' => 'warehousemgmt_attr_value_valueInt', 'type' => 'int', 'internal' => 'valueInt'], + 'warehousemgmt_attr_value_valueDec' => ['name' => 'warehousemgmt_attr_value_valueDec', 'type' => 'float', 'internal' => 'valueDec'], + 'warehousemgmt_attr_value_valueDat' => ['name' => 'warehousemgmt_attr_value_valueDat', 'type' => 'DateTime', 'internal' => 'valueDat'], + 'warehousemgmt_attr_value_unit' => ['name' => 'warehousemgmt_attr_value_unit', 'type' => 'string', 'internal' => 'unit'], + 'warehousemgmt_attr_value_deptype' => ['name' => 'warehousemgmt_attr_value_deptype', 'type' => 'int', 'internal' => 'dependingAttributeType'], + 'warehousemgmt_attr_value_depvalue' => ['name' => 'warehousemgmt_attr_value_depvalue', 'type' => 'int', 'internal' => 'dependingAttributeValue'], + ]; + + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + public const HAS_MANY = [ + 'l11n' => [ + 'mapper' => LotAttributeValueL11nMapper::class, + 'table' => 'warehousemgmt_attr_value_l11n', + 'self' => 'warehousemgmt_attr_value_l11n_value', + 'external' => null, + ], + ]; + + /** + * Model to use by the mapper. + * + * @var class-string + * @since 1.0.0 + */ + public const MODEL = AttributeValue::class; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'warehousemgmt_attr_value'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'warehousemgmt_attr_value_id'; +} diff --git a/Models/Stock.php b/Models/Stock.php index c1f45e7..9a7d3a6 100755 --- a/Models/Stock.php +++ b/Models/Stock.php @@ -44,7 +44,7 @@ class Stock public int $unit = 0; - public Address $address; + public ?Address $address = null; /** * Constructor. diff --git a/Models/StockLocationMapper.php b/Models/StockLocationMapper.php index 8518840..177dec6 100755 --- a/Models/StockLocationMapper.php +++ b/Models/StockLocationMapper.php @@ -39,6 +39,7 @@ final class StockLocationMapper extends DataMapperFactory 'warehousemgmt_stocklocation_id' => ['name' => 'warehousemgmt_stocklocation_id', 'type' => 'int', 'internal' => 'id'], 'warehousemgmt_stocklocation_name' => ['name' => 'warehousemgmt_stocklocation_name', 'type' => 'string', 'internal' => 'name'], 'warehousemgmt_stocklocation_stock' => ['name' => 'warehousemgmt_stocklocation_stock', 'type' => 'int', 'internal' => 'stock'], + 'warehousemgmt_stocklocation_type' => ['name' => 'warehousemgmt_stocklocation_type', 'type' => 'int', 'internal' => 'type'], 'warehousemgmt_stocklocation_x' => ['name' => 'warehousemgmt_stocklocation_x', 'type' => 'int', 'internal' => 'x'], 'warehousemgmt_stocklocation_y' => ['name' => 'warehousemgmt_stocklocation_y', 'type' => 'int', 'internal' => 'y'], 'warehousemgmt_stocklocation_z' => ['name' => 'warehousemgmt_stocklocation_z', 'type' => 'int', 'internal' => 'z'], diff --git a/Models/StockShelfMapper.php b/Models/StockShelfMapper.php index 3560e5e..011cafa 100755 --- a/Models/StockShelfMapper.php +++ b/Models/StockShelfMapper.php @@ -39,6 +39,7 @@ final class StockShelfMapper extends DataMapperFactory 'warehousemgmt_stockshelf_id' => ['name' => 'warehousemgmt_stockshelf_id', 'type' => 'int', 'internal' => 'id'], 'warehousemgmt_stockshelf_name' => ['name' => 'warehousemgmt_stockshelf_name', 'type' => 'string', 'internal' => 'name'], 'warehousemgmt_stockshelf_location' => ['name' => 'warehousemgmt_stockshelf_location', 'type' => 'int', 'internal' => 'location'], + 'warehousemgmt_stockshelf_type' => ['name' => 'warehousemgmt_stockshelf_type', 'type' => 'int', 'internal' => 'type'], 'warehousemgmt_stockshelf_x' => ['name' => 'warehousemgmt_stockshelf_x', 'type' => 'int', 'internal' => 'x'], 'warehousemgmt_stockshelf_y' => ['name' => 'warehousemgmt_stockshelf_y', 'type' => 'int', 'internal' => 'y'], 'warehousemgmt_stockshelf_z' => ['name' => 'warehousemgmt_stockshelf_z', 'type' => 'int', 'internal' => 'z'], diff --git a/Models/StockType.php b/Models/StockType.php index df06d43..43edddb 100644 --- a/Models/StockType.php +++ b/Models/StockType.php @@ -14,7 +14,8 @@ declare(strict_types=1); namespace Modules\WarehouseManagement\Models; -use Modules\Admin\Models\Address; +use phpOMS\Localization\BaseStringL11n; +use phpOMS\Localization\ISO639x1Enum; /** * Warehouse class. @@ -41,4 +42,68 @@ class StockType * @since 1.0.0 */ public string $name = ''; + + /** + * Localization + * + * @var string|BaseStringL11n + */ + protected string | BaseStringL11n $l11n; + + /** + * Set l11n + * + * @param string|BaseStringL11n $l11n Tag article l11n + * @param string $lang Language + * + * @return void + * + * @since 1.0.0 + */ + public function setL11n(string | BaseStringL11n $l11n, string $lang = ISO639x1Enum::_EN) : void + { + if ($l11n instanceof BaseStringL11n) { + $this->l11n = $l11n; + } elseif (isset($this->l11n) && $this->l11n instanceof BaseStringL11n) { + $this->l11n->content = $l11n; + $this->l11n->setLanguage($lang); + } else { + $this->l11n = new BaseStringL11n(); + $this->l11n->content = $l11n; + $this->l11n->ref = $this->id; + $this->l11n->setLanguage($lang); + } + } + + /** + * @return string + * + * @since 1.0.0 + */ + public function getL11n() : string + { + if (!isset($this->l11n)) { + return ''; + } + + return $this->l11n instanceof BaseStringL11n ? $this->l11n->content : $this->l11n; + } + + /** + * {@inheritdoc} + */ + public function toArray() : array + { + return [ + 'id' => $this->id, + ]; + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() : mixed + { + return $this->toArray(); + } } diff --git a/Models/StockTypeL11nMapper.php b/Models/StockTypeL11nMapper.php new file mode 100644 index 0000000..0b42791 --- /dev/null +++ b/Models/StockTypeL11nMapper.php @@ -0,0 +1,69 @@ + + */ +final class StockTypeL11nMapper extends DataMapperFactory +{ + /** + * Columns. + * + * @var array + * @since 1.0.0 + */ + public const COLUMNS = [ + 'warehousemgmt_stock_type_l11n_id' => ['name' => 'warehousemgmt_stock_type_l11n_id', 'type' => 'int', 'internal' => 'id'], + 'warehousemgmt_stock_type_l11n_name' => ['name' => 'warehousemgmt_stock_type_l11n_name', 'type' => 'string', 'internal' => 'content', 'autocomplete' => true], + 'warehousemgmt_stock_type_l11n_type' => ['name' => 'warehousemgmt_stock_type_l11n_type', 'type' => 'int', 'internal' => 'ref'], + 'warehousemgmt_stock_type_l11n_language' => ['name' => 'warehousemgmt_stock_type_l11n_language', 'type' => 'string', 'internal' => 'language'], + ]; + + /** + * Primary table. + * + * @var string + * @since 1.0.0 + */ + public const TABLE = 'warehousemgmt_stock_type_l11n'; + + /** + * Primary field name. + * + * @var string + * @since 1.0.0 + */ + public const PRIMARYFIELD = 'warehousemgmt_stock_type_l11n_id'; + + /** + * Model to use by the mapper. + * + * @var class-string + * @since 1.0.0 + */ + public const MODEL = BaseStringL11n::class; +} diff --git a/Models/StockTypeMapper.php b/Models/StockTypeMapper.php index d47ddf5..edbf0b0 100644 --- a/Models/StockTypeMapper.php +++ b/Models/StockTypeMapper.php @@ -25,10 +25,10 @@ use phpOMS\DataStorage\Database\Mapper\DataMapperFactory; * @link https://jingga.app * @since 1.0.0 * - * @template T of Stock + * @template T of StockType * @extends DataMapperFactory */ -final class StockMapper extends DataMapperFactory +final class StockTypeMapper extends DataMapperFactory { /** * Columns. @@ -41,6 +41,22 @@ final class StockMapper extends DataMapperFactory 'warehousemgmt_stock_type_name' => ['name' => 'warehousemgmt_stock_type_name', 'type' => 'string', 'internal' => 'name'], ]; + /** + * Has many relation. + * + * @var array + * @since 1.0.0 + */ + public const HAS_MANY = [ + 'l11n' => [ + 'mapper' => StockTypeL11nMapper::class, + 'table' => 'warehousemgmt_stock_type_l11n', + 'self' => 'warehousemgmt_stock_type_l11n_type', + 'column' => 'content', + 'external' => null, + ], + ]; + /** * Primary table. * @@ -56,4 +72,12 @@ final class StockMapper extends DataMapperFactory * @since 1.0.0 */ public const PRIMARYFIELD = 'warehousemgmt_stock_type_id'; + + /** + * Model to use by the mapper. + * + * @var class-string + * @since 1.0.0 + */ + public const MODEL = StockType::class; } diff --git a/Theme/Backend/Lang/en.lang.php b/Theme/Backend/Lang/en.lang.php index 974a8c2..5ea67f2 100755 --- a/Theme/Backend/Lang/en.lang.php +++ b/Theme/Backend/Lang/en.lang.php @@ -43,4 +43,5 @@ return ['WarehouseManagement' => [ 'Week' => 'Week', 'Year' => 'Year', 'Zip' => 'Zip', + 'Types' => 'Types', ]]; diff --git a/Theme/Backend/stock-list.tpl.php b/Theme/Backend/stock-list.tpl.php index 0b4ad4f..efdd558 100755 --- a/Theme/Backend/stock-list.tpl.php +++ b/Theme/Backend/stock-list.tpl.php @@ -27,7 +27,6 @@ echo $this->data['nav']->render(); ?> getHtml('ID', '0', '0'); ?> - getHtml('Type'); ?> getHtml('Name'); ?> $value) : @@ -36,11 +35,10 @@ echo $this->data['nav']->render(); ?> ?> id; ?> - type; ?> name; ?> - getHtml('Empty', '0', '0'); ?> + getHtml('Empty', '0', '0'); ?> diff --git a/Theme/Backend/stock-location.tpl.php b/Theme/Backend/stock-location.tpl.php index a34953b..5af5f61 100755 --- a/Theme/Backend/stock-location.tpl.php +++ b/Theme/Backend/stock-location.tpl.php @@ -20,7 +20,7 @@ echo $this->data['nav']->render();
printHtml($location->name); ?>
-
+
\ No newline at end of file diff --git a/Theme/Backend/stock-type-list.tpl.php b/Theme/Backend/stock-type-list.tpl.php new file mode 100644 index 0000000..5627633 --- /dev/null +++ b/Theme/Backend/stock-type-list.tpl.php @@ -0,0 +1,47 @@ +data['types'] ?? []; + +echo $this->data['nav']->render(); ?> + +
+
+
+
getHtml('Stocks'); ?>
+
+ + + + + $value) : + ++$count; + $url = UriFactory::build('{/base}/warehouse/stock/type?id=' . $value->id); + ?> + +
getHtml('ID', '0', '0'); ?> + getHtml('Name'); ?> +
id; ?> + printHtml($value->getL11n()); ?> + + +
getHtml('Empty', '0', '0'); ?> + +
+
+
+
+
diff --git a/Theme/Backend/stock-type-profile.tpl.php b/Theme/Backend/stock-type-profile.tpl.php new file mode 100644 index 0000000..f684710 --- /dev/null +++ b/Theme/Backend/stock-type-profile.tpl.php @@ -0,0 +1,93 @@ +data['type']; + +echo $this->data['nav']->render(); +?> +
+
+
+
getHtml('Type'); ?>
+
+
+ + +
+
+
+
+ +
+
+
getHtml('Localizations'); ?>
+
+ + + + + + data['l11nValues']; + foreach ($itemL11n as $value) : ++$c; ?> + + +
+ getHtml('ID', '0', '0'); ?> + getHtml('Name'); ?> + getHtml('Language'); ?> + getHtml('Localization'); ?> +
+ + type->isRequired) : ?> + + + + + + + + id; ?> + printHtml($value->type->title); ?> + printHtml($value->getLanguage()); ?> + printHtml(\substr($value->content, 0, 100))); ?> + + +
getHtml('Empty', '0', '0'); ?> + +
+
+
+
+
diff --git a/Theme/Backend/stock.tpl.php b/Theme/Backend/stock.tpl.php index 62510d6..d686e4e 100755 --- a/Theme/Backend/stock.tpl.php +++ b/Theme/Backend/stock.tpl.php @@ -18,9 +18,14 @@ echo $this->data['nav']->render(); ?>
-
-
printHtml($stock->name); ?>
+
+
getHtml('Stock'); ?>
+
+ + +
+
\ No newline at end of file