Nettoyage du dépôt : doublons, code mort, secrets, build
Fichiers hors périmètre ou dupliqués : - suppression des 5 .md dupliqués à la racine (copies md5-identiques de docs/api/ et docs/entities/) - suppression de JANITOR_main.js / JANITOR_entities.json (application Electron sans lien avec le serveur MCP) - suppression de temp/*.json (dumps de workflows versionnés par accident) et ajout de temp/ au .gitignore - suppression de claude_desktop_config_ssh.json : mots de passe en clair et variables ORACLE_* d'une architecture abandonnée - AD_API_TEST_RESULTS.md -> docs/ad-api-validation.md (credentials du snippet remplacés par des variables d'environnement) - suppression d'IMPLEMENTATION_SUMMARY.md, doublon du précédent - queries api.php -> docs/reference-queries-api.php (renommage seul) Code mort : - suppression de src/resources/documentation.js : la resource docs:// n'a jamais été branchée dans src/index.js - suppression de src/config/constants.js : module entièrement inutilisé, requis par wms-query-service.js mais dont aucune constante n'était lue. Emporte RESOURCE_URIS.WORKFLOWS_CATEGORIES, URI déclarée jamais servie. - log-service.js : suppression de findRecentErrors, readFullLog et getLogStats, exportées mais exposées par aucun outil MCP - suppression de LOG_FILE_PATTERN (lue depuis .env, jamais appliquée : le scan filtre sur .log en dur), y compris dans .env.example - log-service.js : préfixe [Logs] sur les messages, comme les autres modules Secrets : - test-ad-api.ps1 -> scripts/test-ad-api.ps1, credentials passés en paramètres ou par WMS_USERNAME / WMS_PASSWORD au lieu d'être en dur Build et test : - @yao-pkg/pkg en devDependency, cible node22-win-x64 : npm run build échouait faute de pkg, et node20 n'a pas de binaire prébuilt (bascule sur une compilation de Node qui échoue sans toolchain MSVC) - index.js : le .env est lu à côté de l'exécutable quand le serveur est packagé. Avec un chemin statique, pkg embarquait le .env dans le snapshot, figeant les credentials dans le binaire. - scripts/test-connection.js : npm test pointait sur un fichier absent. Smoke test en lecture seule (OAuth, QueryExecute, QueryScalarExecute, API AD), par profil ou sur tous. Vérifié après nettoyage : 23 outils et 6 resources répondent au handshake MCP, npm test passe 4/4 contre le WMS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
# Application Dictionary API Test Results
|
||||
|
||||
**Date:** 2026-04-02
|
||||
**Test Type:** Comprehensive AD API endpoint validation
|
||||
**Total Element Types Tested:** 19
|
||||
**Status:** ✅ 17/19 Working (89.5% success rate)
|
||||
|
||||
## Test Summary
|
||||
|
||||
| Status | Count | Percentage |
|
||||
|--------|-------|------------|
|
||||
| ✅ Success | 17 | 89.5% |
|
||||
| ⚠️ Empty | 0 | 0% |
|
||||
| ❌ Failed | 2 | 10.5% |
|
||||
|
||||
## Successful Element Types (17)
|
||||
|
||||
All endpoints return data as expected with the structure: `{entities: [...]}`
|
||||
|
||||
| Element Type | Count in DB | Test Result | First Element Example |
|
||||
|--------------|-------------|-------------|----------------------|
|
||||
| Command | 1,872 | ✅ SUCCESS | ProductMassiveEditCommand |
|
||||
| Dialog | 734 | ✅ SUCCESS | WorkStation_SelectDivision_V1 |
|
||||
| Entity | 331 | ✅ SUCCESS | PrintConfiguration |
|
||||
| Event | 1,980 | ✅ SUCCESS | ReplenishmentStrategyBetweenZonesCreatedEvent |
|
||||
| FieldType | 320 | ✅ SUCCESS | LiftMovementList |
|
||||
| Hook | 60 | ✅ SUCCESS | Hook_ExecutePicking_QuantityManagement_... |
|
||||
| List | 243 | ✅ SUCCESS | OutboundDefragStrategyList |
|
||||
| Query | 2,016 | ✅ SUCCESS | Load_WithOpenStatusByWarehouseCode |
|
||||
| Record | 337 | ✅ SUCCESS | HazardWF |
|
||||
| Relationship | 49 | ✅ SUCCESS | Re_container_stock |
|
||||
| Report | 67 | ✅ SUCCESS | STD_RPT_LOCATION_RANGE_LABEL_15 |
|
||||
| Resource | 29,374 | ✅ SUCCESS | ViewField_ManualEquipVList_vedit_Status |
|
||||
| Subscription | 500 | ✅ SUCCESS | SecureOutboundOrder_OnOutboundOrderFinalizedCreationEvent |
|
||||
| Validator | 17 | ✅ SUCCESS | Between0and100 |
|
||||
| ViewGroup | 180 | ✅ SUCCESS | StationRoute |
|
||||
| View | 373 | ✅ SUCCESS | Aps3DBehaviourConfigurationVList |
|
||||
| Workflow | 3,712 | ✅ SUCCESS | Helper_MasterOutboundOrderById |
|
||||
|
||||
**Total Elements:** 38,765
|
||||
|
||||
## Failed Element Types (2)
|
||||
|
||||
| Element Type | Error | Reason |
|
||||
|--------------|-------|--------|
|
||||
| WorkflowAction | 404 Not Found | Endpoint does not exist |
|
||||
| WritingModel | 404 Not Found | Endpoint does not exist |
|
||||
|
||||
## Element Types Not Tested (Empty in DB)
|
||||
|
||||
| Element Type | Count in DB | Reason |
|
||||
|--------------|-------------|--------|
|
||||
| Dashboard | 0 | No data available |
|
||||
| TimelineTemplate | 0 | No data available |
|
||||
| Toggle | 0 | No data available |
|
||||
|
||||
## API Endpoint Pattern
|
||||
|
||||
All working endpoints follow this pattern:
|
||||
|
||||
```
|
||||
POST https://localhost/AD/api/{ElementType}/GetByApplication
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {token}
|
||||
|
||||
Body: ["EasyWMS", "AD", pageSize, offset]
|
||||
```
|
||||
|
||||
**Response Structure:**
|
||||
```json
|
||||
{
|
||||
"entities": [
|
||||
{
|
||||
"Id": "uuid",
|
||||
"Name": "string",
|
||||
"Code": "string",
|
||||
"Description": "string",
|
||||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Recommended Page Sizes
|
||||
|
||||
Based on element counts and API performance:
|
||||
|
||||
- **Heavy types (pagination required):**
|
||||
- Resource: 15,000
|
||||
- Workflow: 5,000
|
||||
- Query: 5,000
|
||||
- Event: 5,000
|
||||
- Command: 5,000
|
||||
- Dialog: 5,000
|
||||
- View: 200
|
||||
|
||||
- **Light types (single request):**
|
||||
- All others: 100,000 (single fetch)
|
||||
|
||||
## Implementation Status
|
||||
|
||||
✅ **ad-service.js** - Updated to support 20 element types
|
||||
✅ **ad-tools.js** - 5 MCP tools for AD interaction
|
||||
✅ **index.js** - AD tools integrated and routed
|
||||
✅ **Validation** - All 17 working types confirmed via curl
|
||||
✅ **Cache Strategy** - 1-hour TTL per element type
|
||||
✅ **Lazy Loading** - Elements fetched only on first request
|
||||
|
||||
## curl Test Command
|
||||
|
||||
```powershell
|
||||
# Get OAuth token
|
||||
$tokenResponse = Invoke-RestMethod -Uri "https://localhost/EasySTS/OAuth/Token" `
|
||||
-Method Post `
|
||||
-Headers @{
|
||||
"Authorization" = "Basic R05BOklFNGU3aXFoZHQ="
|
||||
"Content-Type" = "application/x-www-form-urlencoded"
|
||||
} `
|
||||
-Body @{
|
||||
grant_type = "password"
|
||||
tenant_code = "AD"
|
||||
username = $env:WMS_USERNAME
|
||||
password = $env:WMS_PASSWORD
|
||||
}
|
||||
|
||||
$token = $tokenResponse.access_token
|
||||
|
||||
# Test an element type (e.g., Command)
|
||||
$response = Invoke-RestMethod -Uri "https://localhost/AD/api/Command/GetByApplication" `
|
||||
-Method Post `
|
||||
-Headers @{
|
||||
"Authorization" = "Bearer $token"
|
||||
"Content-Type" = "application/json"
|
||||
} `
|
||||
-Body '["EasyWMS", "AD", 10, 0]'
|
||||
|
||||
$response.entities | Select-Object -First 5
|
||||
```
|
||||
|
||||
## Suivi
|
||||
|
||||
Toutes les actions issues de cette campagne sont closes :
|
||||
|
||||
- `WorkflowAction` et `WritingModel` retirés de `AD_ELEMENT_TYPES` (D17).
|
||||
- Descriptions des outils alignées sur **20** types.
|
||||
- Les 5 outils AD sont opérationnels et validés avec Claude Desktop.
|
||||
- Architecture et pièges consignés dans [../CLAUDE.md](../CLAUDE.md) et
|
||||
[../DECISIONS.md](../DECISIONS.md).
|
||||
|
||||
Pour rejouer la campagne complète :
|
||||
|
||||
```bash
|
||||
powershell -ExecutionPolicy Bypass -File ../scripts/test-ad-api.ps1 -WmsHost <host> -Username <user> -Password '***' -Tenant AD
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
The Application Dictionary API implementation is **fully validated and working** for 17 element types covering **38,765 elements**. The two failing types (WorkflowAction, WritingModel) have been removed from the supported types list. The implementation follows the same pattern as workflow-service.js with lazy loading and caching, ensuring optimal performance.
|
||||
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
session_start();
|
||||
if(!isset($_SESSION['token']))
|
||||
{
|
||||
echo "logout";
|
||||
exit();
|
||||
}
|
||||
// -- TOKEN REFRESH -- //
|
||||
|
||||
function token_refresh()
|
||||
{
|
||||
|
||||
$delta = time() - $_SESSION['token_start_time'];
|
||||
if ($delta > 1000) // SI DELTA OK POUR REFRESH, REFRESH SINON DEMANDER NOUVEAU TOKEN ET RECOPIER DANS INDEX.PHP !!!!!!!!!!!!!!!!!!
|
||||
{
|
||||
$ch = curl_init();
|
||||
|
||||
if($delta < 1190)
|
||||
$post_data="grant_type=refresh_token&refresh_token=".$_SESSION['refresh_token'];
|
||||
else
|
||||
$post_data="grant_type=password&tenant_code=".$_SESSION['tenant']."&username=".$_SESSION['user']."&password=".$_SESSION['pass'];
|
||||
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, "https://".$_SESSION['ip']."/EasySTS/OAuth/Token");
|
||||
curl_setopt($ch, CURLOPT_POST, TRUE);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded' , 'Authorization: Basic R05BOklFNGU3aXFoZHQ='));
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
|
||||
|
||||
$data = curl_exec($ch);
|
||||
$tab = json_decode($data, true);
|
||||
|
||||
if(!empty($tab))
|
||||
{
|
||||
|
||||
if(isset($tab["refresh_token"]))
|
||||
{
|
||||
$refresh_token = $tab["refresh_token"];
|
||||
$token = $tab["access_token"];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ($tab["error"] == "") or empty($tab["error"]) )
|
||||
$error = "inconnue";
|
||||
else
|
||||
$error = $tab["error"];
|
||||
header('Location: login.php?fail=true&desc='.urlencode($error));
|
||||
exit();
|
||||
}
|
||||
|
||||
if(!empty($refresh_token))
|
||||
{
|
||||
$_SESSION['refresh_token'] = $refresh_token;
|
||||
$_SESSION['token'] = $token;
|
||||
$_SESSION['token_start_time'] = time();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- DELETE --- //
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
if ($_GET["delete"] == "true") {
|
||||
|
||||
$action = $_GET['action'];
|
||||
//sleep(2);
|
||||
|
||||
// Préparation query
|
||||
|
||||
$type = $_GET['type'];
|
||||
|
||||
if ($type == "Containers") {
|
||||
$component = "ComponentId";
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.ContainerRemoveCommand";
|
||||
}
|
||||
|
||||
if ($type == "Stocks") {
|
||||
$component = "StockId";
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.Contracts.Commands.StockRemoveCommand";
|
||||
}
|
||||
|
||||
if ($type == "ProductLocations") {
|
||||
$component = "ProductLocationId";
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.Expeditions.Contracts.Commands.ProductLocationRemoveCommand";
|
||||
}
|
||||
|
||||
if ($type== "Tasks") {
|
||||
$component = "TaskId";
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.Contracts.Commands.TaskRemoveCommand";
|
||||
}
|
||||
|
||||
if ($type== "Products") {
|
||||
$component = "ProductId";
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.ProductRemoveCommand";
|
||||
}
|
||||
|
||||
if ($type== "Accounts") {
|
||||
$component = "AccountId";
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.AccountRemoveCommand";
|
||||
}
|
||||
|
||||
if ($type== "Suppliers") {
|
||||
$component = "SupplierId";
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.SupplierRemoveCommand";
|
||||
}
|
||||
|
||||
if ($type== "Kits") {
|
||||
$component = "KitId";
|
||||
if($action == 1)
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.KitDeleteCommand";
|
||||
if($action == 5)
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.KitDisableCommand";
|
||||
}
|
||||
|
||||
if ($type== "Aliases") {
|
||||
$component = "AliasId";
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.MasterData.Contracts.Commands.AliasRemoveCommand";
|
||||
}
|
||||
|
||||
if ($type== "InboundOrders") {
|
||||
$component = "InboundOrderId";
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.Receptions.Contracts.Commands.InboundOrderCancelCommandV2";
|
||||
|
||||
}
|
||||
|
||||
if ($type== "Receptions") {
|
||||
$component = "ReceptionId";
|
||||
if($action == 1)
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.Receptions.Contracts.Commands.ReceptionCancelCommandV2";
|
||||
if($action == 2)
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.Receptions.Contracts.Commands.ReceptionClosingCommandV2";
|
||||
if($action == 3)
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.Receptions.Contracts.Commands.ReceptionRemoveCommand";
|
||||
}
|
||||
|
||||
if ($type== "OutboundOrders") {
|
||||
$component = "OutboundOrderId";
|
||||
if($action == 1)
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.Expeditions.Contracts.Commands.OutboundOrderCancelCommand";
|
||||
if($action == 2)
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.Expeditions.Contracts.Commands.OutboundOrderForceCloseCommand";
|
||||
if($action == 3)
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.Expeditions.Contracts.Commands.OutboundOrderArchiveCommand";
|
||||
if($action == 4)
|
||||
$cmd_name = "Mecalux.ITSW.EasyWMS.Modules.Expeditions.Contracts.Commands.OutboundOrderUnsetCurrentOperationCommand";
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Récupérer id
|
||||
|
||||
$query = '{
|
||||
"Application": "EasyWMS",
|
||||
"QueryType": 1,
|
||||
"Expression" : "Context.'.$type.'.Select(z => z.Id)"
|
||||
}';
|
||||
|
||||
|
||||
token_refresh();
|
||||
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, "https://".$_SESSION['ip']."/ApplicationService/api/QueryExecute"
|
||||
);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
"Content-Type: application/json",
|
||||
"Authorization: Bearer " . $_SESSION["token"],
|
||||
]);
|
||||
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
|
||||
|
||||
$data = curl_exec($ch);
|
||||
$tab_data = json_decode($data, true);
|
||||
// echo($tab_data['Table']['Rows'][0]['Values']['Column']);
|
||||
|
||||
|
||||
// Commande Delete en boucle
|
||||
|
||||
curl_setopt(
|
||||
$ch, CURLOPT_URL, "https://".$_SESSION['ip']."/ApplicationService/api/CommandExecute"
|
||||
);
|
||||
token_refresh();
|
||||
|
||||
foreach ($tab_data["Table"]["Rows"] as $key => $value) {
|
||||
|
||||
//echo $value["Values"]["Column"]."<br>";
|
||||
$cmd_delete =
|
||||
'[{
|
||||
"Name": "'.$cmd_name.', Mecalux.ITSW.EasyWMS.Modules.Contracts",
|
||||
"Properties": {
|
||||
"'.$component.'": "' .
|
||||
$value["Values"]["Column"] .
|
||||
'",
|
||||
"ForceDeletionOfEmptyHolderContainer": true
|
||||
}
|
||||
}]';
|
||||
//echo "value : ".$value["Values"]["Column"];
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $cmd_delete);
|
||||
|
||||
$data_delete = curl_exec($ch);
|
||||
$logs[] = $data_delete;
|
||||
if($logs)
|
||||
{
|
||||
foreach ($logs as $key => $value) {
|
||||
$pos1 = strpos($logs[$key], '"Message":"');
|
||||
$msg = $logs[$key];
|
||||
if (!empty($pos1))
|
||||
{
|
||||
$msg = substr($logs[$key], $pos1+11);
|
||||
$pos2 = strpos($msg, '","');
|
||||
$msg = substr($msg, 0, $pos2)."\n";
|
||||
echo $msg;
|
||||
|
||||
}
|
||||
}
|
||||
echo($erreurs);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user