Freitext Zeilen Unterstützung hinzugefügt

This commit is contained in:
Eduard Wisch 2026-01-30 19:22:04 +01:00
parent 209ce1e3f8
commit 0cf74ff550
21 changed files with 766 additions and 656 deletions

0
.gitignore vendored Normal file → Executable file
View file

0
.idea/SupplierLink3.iml Normal file → Executable file
View file

View file

@ -0,0 +1,10 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</component>

0
.idea/modules.xml Executable file → Normal file
View file

0
.idea/php.xml Executable file → Normal file
View file

6
.idea/sqldialects.xml Executable file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="file://$PROJECT_DIR$/class/actions_supplierlink3.class.php" dialect="GenericSQL" />
</component>
</project>

0
.idea/supplierlink3.iml Executable file → Normal file
View file

0
.idea/vcs.xml Executable file → Normal file
View file

0
COPYING Executable file → Normal file
View file

0
ChangeLog.md Executable file → Normal file
View file

239
README.md Executable file → Normal file
View file

@ -1,96 +1,217 @@
# SUPPLIERLINK3 FOR [DOLIBARR ERP & CRM](https://www.dolibarr.org)
# SupplierLink3 for [Dolibarr ERP & CRM](https://www.dolibarr.org)
**Version 2.0** | **License: GPL v3** | **Author: Eduard Wisch**
Dolibarr module for linking supplier webshops with products and displaying stock levels.
## Features
Description of the module...
### Shop Links
- Direct access to supplier webshops from within Dolibarr
- Automatic URL generation with supplier article number
- Multi-supplier support with popup selection (sorted by price)
- Configurable shop icon (FontAwesome)
- Same supplier opens in same browser tab
<!--
![Screenshot supplierlink3](img/screenshot_supplierlink3.png?raw=true "SupplierLink3"){imgmd}
-->
### Stock Display
Colored badges for quick overview:
- **Red**: Out of stock (< 1)
- **Orange**: Below minimum stock (alert threshold)
- **Gray**: Below desired stock
- **Green**: Sufficient stock
Other external modules are available on [Dolistore.com](https://www.dolistore.com).
## Translations
Translations can be completed manually by editing files in the module directories under `langs`.
<!--
This module contains also a sample configuration for Transifex, under the hidden directory [.tx](.tx), so it is possible to manage translation using this service.
For more information, see the [translator's documentation](https://wiki.dolibarr.org/index.php/Translator_documentation).
There is a [Transifex project](https://transifex.com/projects/p/dolibarr-module-template) for this module.
-->
### Supported Areas
- Customer Orders
- Proposals/Quotes
- Supplier Orders
- Stock Replenishment
- Product Card
### Quick Supplier Order Creation
- "Create Supplier Order" button in customer orders
- Automatic product and quantity transfer
- Supplier reference with customer name and order number
## Installation
Prerequisites: You must have Dolibarr ERP & CRM software installed. You can download it from [Dolistore.org](https://www.dolibarr.org).
You can also get a ready-to-use instance in the cloud from https://saas.dolibarr.org
### From ZIP file
1. Go to menu **Home > Setup > Modules > Deploy external module**
2. Upload the zip file
### Manual Installation
1. Copy module folder to `/custom/supplierlink3/`
2. In Dolibarr: **Setup > Modules > SupplierLink3** - activate
3. On activation, extrafield `shop_url` is created for suppliers
### From the ZIP file and GUI interface
## Configuration
If the module is a ready-to-deploy zip file, so with a name `module_xxx-version.zip` (e.g., when downloading it from a marketplace like [Dolistore](https://www.dolistore.com)),
go to menu `Home> Setup> Modules> Deploy external module` and upload the zip file.
### Admin Center
Settings under **Setup > Modules > SupplierLink3 > Settings**
<!--
#### Display Settings
Enable/disable the function for each area:
- Customer Orders
- Proposals
- Supplier Orders
- Stock Replenishment
- Product Card
Note: If this screen tells you that there is no "custom" directory, check that your setup is correct:
#### Icon Settings
Customizable FontAwesome icons:
- **Shop Icon**: Default `fas fa-store`
- **Stock Icon**: Optional
- In your Dolibarr installation directory, edit the `htdocs/conf/conf.php` file and check that following lines are not commented:
#### Debug Mode
- Disabled by default
- When enabled, writes to `/tmp/supplierlink3_debug.log`
```php
//$dolibarr_main_url_root_alt ...
//$dolibarr_main_document_root_alt ...
```
### Setting up Shop URL for Suppliers
1. Open supplier > Edit
2. Fill extrafield "Shop URL" (e.g. `https://shop.supplier.com/article/`)
3. The supplier article number is automatically appended
- Uncomment them if necessary (delete the leading `//`) and assign the proper value according to your Dolibarr installation
## Usage
For example :
### In Orders/Proposals
- Click shop icon next to stock level
- Multiple suppliers: Dropdown with price comparison
- Same supplier opens in same browser tab
- UNIX:
```php
$dolibarr_main_url_root_alt = '/custom';
$dolibarr_main_document_root_alt = '/var/www/Dolibarr/htdocs/custom';
```
### Creating Supplier Order
1. Open customer order
2. Click "Create Supplier Order" button
3. Select supplier
4. Select products
5. Create order
- Windows:
```php
$dolibarr_main_url_root_alt = '/custom';
$dolibarr_main_document_root_alt = 'C:/My Web Sites/Dolibarr/htdocs/custom';
```
-->
## Technical Details
<!--
### Hooks
- `ordersuppliercard` - Supplier Orders
- `ordercard` - Customer Orders
- `propalcard` - Proposals
- `productcard` - Product Card
- `productpricecard` - Product Prices
- `stockreplenishlist` - Replenishment List
### From a GIT repository
### Database
Uses extrafield `shop_url` in `llx_societe_extrafields`.
Clone the repository in `$dolibarr_main_document_root_alt/supplierlink3`
```shell
cd ....../custom
git clone git@github.com:gitlogin/supplierlink3.git supplierlink3
### File Structure
```
supplierlink3/
├── admin/
│ ├── setup.php # Settings
│ └── about.php # About page
├── class/
│ └── actions_supplierlink3.class.php # Hook implementation
├── core/modules/
│ └── modSupplierLink3.class.php # Module definition
├── js/
│ └── replenish.js # JavaScript for replenishment
├── langs/
│ ├── de_DE/supplierlink3.lang
│ └── en_US/supplierlink3.lang
├── lib/
│ └── supplierlink3.lib.php
└── create_supplier_order.php # Create supplier order
```
-->
## Changelog
### Final steps
### Version 2.0
- Admin center completely redesigned
- Settings per area (enable/disable)
- Configurable icons (FontAwesome)
- Debug mode disabled by default
- Bilingual (German/English)
- Stock replenishment list integrated
- Improved icon alignment
Using your browser:
### Version 1.0
- Initial release
- Shop links in orders
- Stock badges
- Supplier order from customer order
- Log into Dolibarr as a super-administrator
- Go to "Setup"> "Modules"
- You should now be able to find and enable the module
## Translations
Translations are available in:
- German (de_DE)
- English (en_US)
Additional translations can be added by creating files in `langs/xx_XX/supplierlink3.lang`
## Support
For questions or issues: data@data-it-solution.de
## Licenses
### Main code
### Main Code
GPLv3 or (at your option) any later version. See file COPYING for more information.
### Documentation
All texts and readmes are licensed under [GFDL](https://www.gnu.org/licenses/fdl-1.3.en.html).
All texts and readme's are licensed under [GFDL](https://www.gnu.org/licenses/fdl-1.3.en.html).
---
# SupplierLink3 für [Dolibarr ERP & CRM](https://www.dolibarr.org) (Deutsch)
**Version 2.0** | **Lizenz: GPL v3** | **Autor: Eduard Wisch**
Dolibarr-Modul zur Verknüpfung von Lieferanten-Webshops mit Produkten und Anzeige von Lagerbeständen.
## Funktionen
### Shop-Links
- Direkter Zugang zu Lieferanten-Webshops aus Dolibarr heraus
- Automatische URL-Generierung mit Lieferanten-Artikelnummer
- Multi-Lieferanten-Unterstützung mit Popup-Auswahl (sortiert nach Preis)
- Konfigurierbares Shop-Symbol (FontAwesome)
- Gleicher Lieferant öffnet sich im gleichen Browser-Tab
### Lagerbestand-Anzeige
Farbige Badges für schnelle Übersicht:
- **Rot**: Nicht auf Lager (< 1)
- **Orange**: Unter Mindestbestand (Alarm-Schwelle)
- **Grau**: Unter Wunschbestand
- **Grün**: Ausreichend auf Lager
### Unterstützte Bereiche
- Kundenaufträge
- Angebote
- Lieferantenbestellungen
- Nachbestellung (Lager)
- Produktkarte
### Schnelle Lieferantenbestellung
- Button "Lieferantenbestellung erstellen" im Kundenauftrag
- Automatische Übernahme von Produkten und Mengen
- Lieferanten-Referenz mit Kundenname und Auftragsnummer
## Konfiguration
### Shop-URL für Lieferanten einrichten
1. Lieferant öffnen > Bearbeiten
2. Extrafeld "Shop URL" ausfüllen (z.B. `https://shop.lieferant.de/artikel/`)
3. Die Lieferanten-Artikelnummer wird automatisch angehängt
### Admin-Center
Einstellungen unter **Einstellungen > Module > SupplierLink3 > Einstellungen**
#### Anzeige-Einstellungen
Aktivieren/Deaktivieren pro Bereich:
- Kundenaufträge
- Angebote
- Lieferantenbestellungen
- Nachbestellung (Lager)
- Produktkarte
#### Symbol-Einstellungen
- **Shop-Symbol**: Standard `fas fa-store`
- **Lagerbestand-Symbol**: Optional
#### Debug-Modus
- Standardmäßig deaktiviert
- Schreibt bei Aktivierung nach `/tmp/supplierlink3_debug.log`

116
admin/about.php Executable file → Normal file
View file

@ -1,7 +1,7 @@
<?php
/* Copyright (C) 2004-2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2025 Eduard Wisch <data@data-it-solution.de>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2025 Eduard Wisch <data@data-it-solution.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -25,11 +25,9 @@
// Load Dolibarr environment
$res = 0;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
@ -44,7 +42,6 @@ if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
// Try main.inc.php using relative path
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
@ -60,14 +57,6 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
require_once '../lib/supplierlink3.lib.php';
/**
* @var Conf $conf
* @var DoliDB $db
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
// Translations
$langs->loadLangs(array("errors", "admin", "supplierlink3@supplierlink3"));
@ -76,43 +65,108 @@ if (!$user->admin) {
accessforbidden();
}
// Parameters
$action = GETPOST('action', 'aZ09');
$backtopage = GETPOST('backtopage', 'alpha');
/*
* Actions
*/
// None
/*
* View
*/
$form = new Form($db);
$help_url = '';
$title = "SupplierLink3Setup";
$title = $langs->trans("SupplierLink3Setup");
llxHeader('', $langs->trans($title), $help_url, '', 0, 0, '', '', '', 'mod-supplierlink3 page-admin_about');
llxHeader('', $title, '', '', 0, 0, '', '', '', 'mod-supplierlink3 page-admin_about');
// Subheader
$linkback = '<a href="'.($backtopage ? $backtopage : DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1').'">'.$langs->trans("BackToModuleList").'</a>';
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
print load_fiche_titre($langs->trans($title), $linkback, 'title_setup');
print load_fiche_titre($title, $linkback, 'title_setup');
// Configuration header
$head = supplierlink3AdminPrepareHead();
print dol_get_fiche_head($head, 'about', $langs->trans($title), 0, 'supplierlink3@supplierlink3');
print dol_get_fiche_head($head, 'about', $title, -1, 'supplierlink3@supplierlink3');
// Module info
dol_include_once('/supplierlink3/core/modules/modSupplierLink3.class.php');
$tmpmodule = new modSupplierLink3($db);
print $tmpmodule->getDescLong();
print '<table class="noborder centpercent">';
// Version
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans('SL3_Version').' & '.$langs->trans('SL3_Author').'</th>';
print '</tr>';
print '<tr class="oddeven">';
print '<td width="30%">'.$langs->trans('SL3_Version').'</td>';
print '<td><strong>'.$tmpmodule->version.'</strong></td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans('SL3_Author').'</td>';
print '<td>Eduard Wisch &lt;data@data-it-solution.de&gt;</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td>'.$langs->trans('SL3_License').'</td>';
print '<td>GPL v3</td>';
print '</tr>';
print '</table>';
print '<br>';
// Features
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th>'.$langs->trans('SL3_Features').'</th>';
print '</tr>';
$features = array(
'SL3_Feature1' => 'fa-store',
'SL3_Feature2' => 'fa-boxes',
'SL3_Feature3' => 'fa-truck-loading',
'SL3_Feature4' => 'fa-users',
);
foreach ($features as $key => $icon) {
print '<tr class="oddeven">';
print '<td><i class="fas '.$icon.'" style="color: #0077b6; margin-right: 10px; width: 20px;"></i>'.$langs->trans($key).'</td>';
print '</tr>';
}
print '</table>';
print '<br>';
// Stock badge legend
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="2">'.$langs->trans('SL3_StockBadges', 'Lagerbestand-Badges').'</th>';
print '</tr>';
print '<tr class="oddeven">';
print '<td width="150"><span class="badge" style="background-color: #dc3545; color: #fff;">0</span></td>';
print '<td>'.$langs->trans('SL3_StockCritical').'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td><span class="badge" style="background-color: #fd7e14; color: #fff;">5</span></td>';
print '<td>'.$langs->trans('SL3_StockWarning').'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td><span class="badge" style="background-color: #6c757d; color: #fff;">15</span></td>';
print '<td>'.$langs->trans('SL3_StockLow').'</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td><span class="badge" style="background-color: #28a745; color: #fff;">42</span></td>';
print '<td>'.$langs->trans('SL3_StockOk').'</td>';
print '</tr>';
print '</table>';
// Page end
print dol_get_fiche_end();
llxFooter();
$db->close();

908
admin/setup.php Executable file → Normal file
View file

@ -25,11 +25,9 @@
// Load Dolibarr environment
$res = 0;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
@ -44,7 +42,6 @@ if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
// Try main.inc.php using relative path
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
@ -58,263 +55,104 @@ if (!$res) {
// Libraries
require_once DOL_DOCUMENT_ROOT."/core/lib/admin.lib.php";
require_once '../lib/supplierlink3.lib.php';
//require_once "../class/myclass.class.php";
/**
* @var Conf $conf
* @var DoliDB $db
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
// Translations
$langs->loadLangs(array("admin", "supplierlink3@supplierlink3"));
// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
/** @var HookManager $hookmanager */
$hookmanager->initHooks(array('supplierlink3setup', 'globalsetup'));
// Access control
if (!$user->admin) {
accessforbidden();
}
// Parameters
$action = GETPOST('action', 'aZ09');
$backtopage = GETPOST('backtopage', 'alpha');
$modulepart = GETPOST('modulepart', 'aZ09'); // Used by actions_setmoduleoptions.inc.php
$value = GETPOST('value', 'alpha');
$label = GETPOST('label', 'alpha');
$scandir = GETPOST('scan_dir', 'alpha');
$type = 'myobject';
$error = 0;
$setupnotempty = 0;
// Access control
if (!$user->admin) {
accessforbidden();
}
// Set this to 1 to use the factory to manage constants. Warning, the generated module will be compatible with version v15+ only
$useFormSetup = 1;
if (!class_exists('FormSetup')) {
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formsetup.class.php';
}
$formSetup = new FormSetup($db);
// Access control
if (!$user->admin) {
accessforbidden();
}
// Enter here all parameters in your setup page
// Setup conf for selection of an URL
$item = $formSetup->newItem('SUPPLIERLINK3_MYPARAM1');
$item->fieldParams['isMandatory'] = 1;
$item->fieldAttr['placeholder'] = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'];
$item->cssClass = 'minwidth500';
// Setup conf for selection of a simple string input
$item = $formSetup->newItem('SUPPLIERLINK3_MYPARAM2');
$item->defaultFieldValue = 'default value';
$item->fieldAttr['placeholder'] = 'A placeholder here';
$item->helpText = 'Tooltip text';
// Setup conf for selection of a simple textarea input but we replace the text of field title
$item = $formSetup->newItem('SUPPLIERLINK3_MYPARAM3');
$item->nameText = $item->getNameText().' more html text ';
// Setup conf for a selection of a Thirdparty
$item = $formSetup->newItem('SUPPLIERLINK3_MYPARAM4');
$item->setAsThirdpartyType();
// Setup conf for a selection of a boolean
$formSetup->newItem('SUPPLIERLINK3_MYPARAM5')->setAsYesNo();
// Setup conf for a selection of an Email template of type thirdparty
$formSetup->newItem('SUPPLIERLINK3_MYPARAM6')->setAsEmailTemplate('thirdparty');
// Setup conf for a selection of a secured key
//$formSetup->newItem('SUPPLIERLINK3_MYPARAM7')->setAsSecureKey();
// Setup conf for a selection of a Product
$formSetup->newItem('SUPPLIERLINK3_MYPARAM8')->setAsProduct();
// Add a title for a new section
$formSetup->newItem('NewSection')->setAsTitle();
$TField = array(
'test01' => $langs->trans('test01'),
'test02' => $langs->trans('test02'),
'test03' => $langs->trans('test03'),
'test04' => $langs->trans('test04'),
'test05' => $langs->trans('test05'),
'test06' => $langs->trans('test06'),
);
// Setup conf for a simple combo list
$formSetup->newItem('SUPPLIERLINK3_MYPARAM9')->setAsSelect($TField);
// Setup conf for a multiselect combo list
$item = $formSetup->newItem('SUPPLIERLINK3_MYPARAM10');
$item->setAsMultiSelect($TField);
$item->helpText = $langs->transnoentities('SUPPLIERLINK3_MYPARAM10');
// Setup conf for a category selection
$formSetup->newItem('SUPPLIERLINK3_CATEGORY_ID_XXX')->setAsCategory('product');
// Setup conf SUPPLIERLINK3_MYPARAM10
$item = $formSetup->newItem('SUPPLIERLINK3_MYPARAM10');
$item->setAsColor();
$item->defaultFieldValue = '#FF0000';
//$item->fieldValue = '';
//$item->fieldAttr = array() ; // fields attribute only for compatible fields like input text
//$item->fieldOverride = false; // set this var to override field output will override $fieldInputOverride and $fieldOutputOverride too
//$item->fieldInputOverride = false; // set this var to override field input
//$item->fieldOutputOverride = false; // set this var to override field output
$item = $formSetup->newItem('SUPPLIERLINK3_MYPARAM11')->setAsHtml();
$item->nameText = $item->getNameText().' more html text ';
$item->fieldInputOverride = '';
$item->helpText = $langs->transnoentities('HelpMessage');
$item->cssClass = 'minwidth500';
$item = $formSetup->newItem('SUPPLIERLINK3_MYPARAM12');
$item->fieldOverride = "Value forced, can't be modified";
$item->cssClass = 'minwidth500';
//$item = $formSetup->newItem('SUPPLIERLINK3_MYPARAM13')->setAsDate(); // Not yet implemented
// End of definition of parameters
$setupnotempty += count($formSetup->items);
$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
$moduledir = 'supplierlink3';
$myTmpObjects = array();
// TODO Scan list of objects to fill this array
$myTmpObjects['myobject'] = array('label' => 'MyObject', 'includerefgeneration' => 0, 'includedocgeneration' => 0, 'class' => 'MyObject');
$tmpobjectkey = GETPOST('object', 'aZ09');
if ($tmpobjectkey && !array_key_exists($tmpobjectkey, $myTmpObjects)) {
accessforbidden('Bad value for object. Hack attempt ?');
}
/*
* Actions
*/
// For retrocompatibility Dolibarr < 15.0
if (versioncompare(explode('.', DOL_VERSION), array(15)) < 0 && $action == 'update' && !empty($user->admin)) {
$formSetup->saveConfFromPost();
}
include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
if ($action == 'updateMask') {
$maskconst = GETPOST('maskconst', 'aZ09');
$maskvalue = GETPOST('maskvalue', 'alpha');
if ($maskconst && preg_match('/_MASK$/', $maskconst)) {
$res = dolibarr_set_const($db, $maskconst, $maskvalue, 'chaine', 0, '', $conf->entity);
if (!($res > 0)) {
$error++;
}
}
if (!$error) {
// Toggle display settings
if ($action == 'set_enable_ordercard') {
$value = GETPOST('value', 'int');
dolibarr_set_const($db, 'SUPPLIERLINK3_ENABLE_ORDERCARD', $value, 'chaine', 0, '', $conf->entity);
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
} else {
setEventMessages($langs->trans("Error"), null, 'errors');
}
} elseif ($action == 'specimen' && $tmpobjectkey) {
$modele = GETPOST('module', 'alpha');
$className = $myTmpObjects[$tmpobjectkey]['class'];
$tmpobject = new $className($db);
'@phan-var-force MyObject $tmpobject';
$tmpobject->initAsSpecimen();
// Search template files
$file = '';
$className = '';
$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
foreach ($dirmodels as $reldir) {
$file = dol_buildpath($reldir."core/modules/supplierlink3/doc/pdf_".$modele."_".strtolower($tmpobjectkey).".modules.php", 0);
if (file_exists($file)) {
$className = "pdf_".$modele."_".strtolower($tmpobjectkey);
break;
}
}
if ($className !== '') {
require_once $file;
$module = new $className($db);
'@phan-var-force ModelePDFMyObject $module';
'@phan-var-force ModelePDFMyObject $module';
if ($module->write_file($tmpobject, $langs) > 0) {
header("Location: ".DOL_URL_ROOT."/document.php?modulepart=supplierlink3-".strtolower($tmpobjectkey)."&file=SPECIMEN.pdf");
return;
} else {
setEventMessages($module->error, null, 'errors');
dol_syslog($module->error, LOG_ERR);
}
} else {
setEventMessages($langs->trans("ErrorModuleNotFound"), null, 'errors');
dol_syslog($langs->trans("ErrorModuleNotFound"), LOG_ERR);
}
} elseif ($action == 'setmod') {
// TODO Check if numbering module chosen can be activated by calling method canBeActivated
if (!empty($tmpobjectkey)) {
$constforval = 'SUPPLIERLINK3_'.strtoupper($tmpobjectkey)."_ADDON";
dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity);
}
} elseif ($action == 'set') {
// Activate a model
$ret = addDocumentModel($value, $type, $label, $scandir);
} elseif ($action == 'del') {
$ret = delDocumentModel($value, $type);
if ($ret > 0) {
if (!empty($tmpobjectkey)) {
$constforval = 'SUPPLIERLINK3_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
if (getDolGlobalString($constforval) == "$value") {
dolibarr_del_const($db, $constforval, $conf->entity);
}
}
}
} elseif ($action == 'setdoc') {
// Set or unset default model
if (!empty($tmpobjectkey)) {
$constforval = 'SUPPLIERLINK3_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
if (dolibarr_set_const($db, $constforval, $value, 'chaine', 0, '', $conf->entity)) {
// The constant that was read before the new set
// We therefore requires a variable to have a coherent view
$conf->global->{$constforval} = $value;
}
// We disable/enable the document template (into llx_document_model table)
$ret = delDocumentModel($value, $type);
if ($ret > 0) {
$ret = addDocumentModel($value, $type, $label, $scandir);
}
}
} elseif ($action == 'unsetdoc') {
if (!empty($tmpobjectkey)) {
$constforval = 'SUPPLIERLINK3_'.strtoupper($tmpobjectkey).'_ADDON_PDF';
dolibarr_del_const($db, $constforval, $conf->entity);
}
header("Location: ".$_SERVER["PHP_SELF"]);
exit;
}
$action = 'edit';
if ($action == 'set_enable_propalcard') {
$value = GETPOST('value', 'int');
dolibarr_set_const($db, 'SUPPLIERLINK3_ENABLE_PROPALCARD', $value, 'chaine', 0, '', $conf->entity);
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
header("Location: ".$_SERVER["PHP_SELF"]);
exit;
}
if ($action == 'set_enable_supplierorder') {
$value = GETPOST('value', 'int');
dolibarr_set_const($db, 'SUPPLIERLINK3_ENABLE_SUPPLIERORDER', $value, 'chaine', 0, '', $conf->entity);
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
header("Location: ".$_SERVER["PHP_SELF"]);
exit;
}
if ($action == 'set_enable_replenish') {
$value = GETPOST('value', 'int');
dolibarr_set_const($db, 'SUPPLIERLINK3_ENABLE_REPLENISH', $value, 'chaine', 0, '', $conf->entity);
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
header("Location: ".$_SERVER["PHP_SELF"]);
exit;
}
if ($action == 'set_enable_productcard') {
$value = GETPOST('value', 'int');
dolibarr_set_const($db, 'SUPPLIERLINK3_ENABLE_PRODUCTCARD', $value, 'chaine', 0, '', $conf->entity);
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
header("Location: ".$_SERVER["PHP_SELF"]);
exit;
}
// Save icon settings
if ($action == 'save_icons') {
$shopIcon = GETPOST('shop_icon', 'alpha');
$stockIcon = GETPOST('stock_icon', 'alpha');
// Validate FontAwesome class format
if (!empty($shopIcon) && preg_match('/^fa[srb]?\s+fa-[\w-]+$/', $shopIcon)) {
dolibarr_set_const($db, 'SUPPLIERLINK3_SHOP_ICON', $shopIcon, 'chaine', 0, '', $conf->entity);
} elseif (empty($shopIcon)) {
dolibarr_del_const($db, 'SUPPLIERLINK3_SHOP_ICON', $conf->entity);
}
if (!empty($stockIcon) && preg_match('/^fa[srb]?\s+fa-[\w-]+$/', $stockIcon)) {
dolibarr_set_const($db, 'SUPPLIERLINK3_STOCK_ICON', $stockIcon, 'chaine', 0, '', $conf->entity);
} elseif (empty($stockIcon)) {
dolibarr_del_const($db, 'SUPPLIERLINK3_STOCK_ICON', $conf->entity);
}
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
header("Location: ".$_SERVER["PHP_SELF"]);
exit;
}
// Debug mode
if ($action == 'setdebug') {
$value = GETPOST('value', 'int');
dolibarr_set_const($db, 'SUPPLIERLINK3_DEBUG_MODE', $value, 'chaine', 0, '', $conf->entity);
setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
header("Location: ".$_SERVER["PHP_SELF"]);
exit;
}
if ($action == 'cleardebuglog') {
$logFile = '/tmp/supplierlink3_debug.log';
if (file_exists($logFile)) {
unlink($logFile);
setEventMessages($langs->trans('SL3_DebugLogCleared'), null, 'mesgs');
}
header("Location: ".$_SERVER["PHP_SELF"]);
exit;
}
/*
@ -323,307 +161,333 @@ $action = 'edit';
$form = new Form($db);
$help_url = '';
$title = "SupplierLink3Setup";
$title = $langs->trans("SupplierLink3Setup");
llxHeader('', $langs->trans($title), $help_url, '', 0, 0, '', '', '', 'mod-supplierlink3 page-admin');
llxHeader('', $title, '', '', 0, 0, '', '', '', 'mod-supplierlink3 page-admin');
// Subheader
$linkback = '<a href="'.($backtopage ? $backtopage : DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1').'">'.$langs->trans("BackToModuleList").'</a>';
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
print load_fiche_titre($langs->trans($title), $linkback, 'title_setup');
print load_fiche_titre($title, $linkback, 'title_setup');
// Configuration header
$head = supplierlink3AdminPrepareHead();
print dol_get_fiche_head($head, 'settings', $langs->trans($title), -1, "supplierlink3@supplierlink3");
print dol_get_fiche_head($head, 'settings', $title, -1, "supplierlink3@supplierlink3");
// Setup page goes here
echo '<span class="opacitymedium">'.$langs->trans("SupplierLink3SetupPage").'</span><br><br>';
print '<span class="opacitymedium">'.$langs->trans('SupplierLink3Description').'</span><br><br>';
// =============================================================================
// DISPLAY SETTINGS
// =============================================================================
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="3">'.$langs->trans('SL3_DisplaySettings').'</th>';
print '</tr>';
/*if ($action == 'edit') {
print $formSetup->generateOutput(true);
print '<br>';
} elseif (!empty($formSetup->items)) {
print $formSetup->generateOutput();
print '<div class="tabsAction">';
print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'">'.$langs->trans("Modify").'</a>';
print '</div>';
}
*/
if (!empty($formSetup->items)) {
print $formSetup->generateOutput(true);
print '<br>';
}
print '<tr class="oddeven">';
print '<td colspan="3" class="opacitymedium">'.$langs->trans('SL3_DisplaySettingsDesc').'</td>';
print '</tr>';
foreach ($myTmpObjects as $myTmpObjectKey => $myTmpObjectArray) {
if (!empty($myTmpObjectArray['includerefgeneration'])) {
// Numbering models
$setupnotempty++;
print load_fiche_titre($langs->trans("NumberingModules", $myTmpObjectArray['label']), '', '');
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<td>'.$langs->trans("Name").'</td>';
print '<td>'.$langs->trans("Description").'</td>';
print '<td class="nowrap">'.$langs->trans("Example").'</td>';
print '<td class="center" width="60">'.$langs->trans("Status").'</td>';
print '<td class="center" width="16">'.$langs->trans("ShortInfo").'</td>';
print '</tr>'."\n";
clearstatcache();
foreach ($dirmodels as $reldir) {
$dir = dol_buildpath($reldir."core/modules/".$moduledir);
if (is_dir($dir)) {
$handle = opendir($dir);
if (is_resource($handle)) {
while (($file = readdir($handle)) !== false) {
if (strpos($file, 'mod_'.strtolower($myTmpObjectKey).'_') === 0 && substr($file, dol_strlen($file) - 3, 3) == 'php') {
$file = substr($file, 0, dol_strlen($file) - 4);
require_once $dir.'/'.$file.'.php';
$module = new $file($db);
'@phan-var-force ModeleNumRefMyObject $module';
// Show modules according to features level
if ($module->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2) {
continue;
}
if ($module->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1) {
continue;
}
if ($module->isEnabled()) {
dol_include_once('/'.$moduledir.'/class/'.strtolower($myTmpObjectKey).'.class.php');
print '<tr class="oddeven"><td>'.$module->getName($langs)."</td><td>\n";
print $module->info($langs);
print '</td>';
// Show example of numbering model
print '<td class="nowrap">';
$tmp = $module->getExample();
if (preg_match('/^Error/', $tmp)) {
$langs->load("errors");
print '<div class="error">'.$langs->trans($tmp).'</div>';
} elseif ($tmp == 'NotConfigured') {
print $langs->trans($tmp);
} else {
print $tmp;
}
print '</td>'."\n";
print '<td class="center">';
$constforvar = 'SUPPLIERLINK3_'.strtoupper($myTmpObjectKey).'_ADDON';
$defaultifnotset = 'thevaluetousebydefault';
$activenumberingmodel = getDolGlobalString($constforvar, $defaultifnotset);
if ($activenumberingmodel == $file) {
// Customer Orders (ordercard)
$enableOrderCard = getDolGlobalInt('SUPPLIERLINK3_ENABLE_ORDERCARD', 1);
print '<tr class="oddeven">';
print '<td>'.$langs->trans('SL3_EnableOrderCard').'</td>';
print '<td class="center" width="80">';
if ($enableOrderCard) {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set_enable_ordercard&token='.newToken().'&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&token='.newToken().'&object='.strtolower($myTmpObjectKey).'&value='.urlencode($file).'">';
print '</a>';
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set_enable_ordercard&token='.newToken().'&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a>';
}
print '</td>';
}
print '</td>';
print '<td class="opacitymedium">'.$langs->trans('SL3_EnableOrderCardDesc').'</td>';
print '</tr>';
$className = $myTmpObjectArray['class'];
$mytmpinstance = new $className($db);
'@phan-var-force MyObject $mytmpinstance';
$mytmpinstance->initAsSpecimen();
// Info
$htmltooltip = '';
$htmltooltip .= ''.$langs->trans("Version").': <b>'.$module->getVersion().'</b><br>';
$nextval = $module->getNextValue($mytmpinstance);
if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval
$htmltooltip .= ''.$langs->trans("NextValue").': ';
if ($nextval) {
if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured') {
$nextval = $langs->trans($nextval);
}
$htmltooltip .= $nextval.'<br>';
} else {
$htmltooltip .= $langs->trans($module->error).'<br>';
}
}
print '<td class="center">';
print $form->textwithpicto('', $htmltooltip, 1, 'info');
print '</td>';
print "</tr>\n";
}
}
}
closedir($handle);
}
}
}
print "</table><br>\n";
}
if (!empty($myTmpObjectArray['includedocgeneration'])) {
/*
* Document templates generators
*/
$setupnotempty++;
$type = strtolower($myTmpObjectKey);
print load_fiche_titre($langs->trans("DocumentModules", $myTmpObjectKey), '', '');
// Load array def with activated templates
$def = array();
$sql = "SELECT nom";
$sql .= " FROM ".$db->prefix()."document_model";
$sql .= " WHERE type = '".$db->escape($type)."'";
$sql .= " AND entity = ".$conf->entity;
$resql = $db->query($sql);
if ($resql) {
$i = 0;
$num_rows = $db->num_rows($resql);
while ($i < $num_rows) {
$array = $db->fetch_array($resql);
array_push($def, $array[0]);
$i++;
}
} else {
dol_print_error($db);
}
print '<table class="noborder centpercent">'."\n";
print '<tr class="liste_titre">'."\n";
print '<td>'.$langs->trans("Name").'</td>';
print '<td>'.$langs->trans("Description").'</td>';
print '<td class="center" width="60">'.$langs->trans("Status")."</td>\n";
print '<td class="center" width="60">'.$langs->trans("Default")."</td>\n";
print '<td class="center" width="38">'.$langs->trans("ShortInfo").'</td>';
print '<td class="center" width="38">'.$langs->trans("Preview").'</td>';
print "</tr>\n";
clearstatcache();
foreach ($dirmodels as $reldir) {
foreach (array('', '/doc') as $valdir) {
$realpath = $reldir."core/modules/".$moduledir.$valdir;
$dir = dol_buildpath($realpath);
if (is_dir($dir)) {
$handle = opendir($dir);
if (is_resource($handle)) {
$filelist = array();
while (($file = readdir($handle)) !== false) {
$filelist[] = $file;
}
closedir($handle);
arsort($filelist);
foreach ($filelist as $file) {
if (preg_match('/\.modules\.php$/i', $file) && preg_match('/^(pdf_|doc_)/', $file)) {
if (file_exists($dir.'/'.$file)) {
$name = substr($file, 4, dol_strlen($file) - 16);
$className = substr($file, 0, dol_strlen($file) - 12);
require_once $dir.'/'.$file;
$module = new $className($db);
'@phan-var-force ModelePDFMyObject $module';
$modulequalified = 1;
if ($module->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2) {
$modulequalified = 0;
}
if ($module->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1) {
$modulequalified = 0;
}
if ($modulequalified) {
print '<tr class="oddeven"><td width="100">';
print(empty($module->name) ? $name : $module->name);
print "</td><td>\n";
if (method_exists($module, 'info')) {
print $module->info($langs); // @phan-suppress-current-line PhanUndeclaredMethod
} else {
print $module->description;
}
print '</td>';
// Active
if (in_array($name, $def)) {
print '<td class="center">'."\n";
print '<a href="'.$_SERVER["PHP_SELF"].'?action=del&token='.newToken().'&value='.urlencode($name).'">';
print img_picto($langs->trans("Enabled"), 'switch_on');
// Proposals (propalcard)
$enablePropalCard = getDolGlobalInt('SUPPLIERLINK3_ENABLE_PROPALCARD', 1);
print '<tr class="oddeven">';
print '<td>'.$langs->trans('SL3_EnablePropalCard').'</td>';
print '<td class="center">';
if ($enablePropalCard) {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set_enable_propalcard&token='.newToken().'&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print '</a>';
print '</td>';
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set_enable_propalcard&token='.newToken().'&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a>';
}
print '</td>';
print '<td class="opacitymedium">'.$langs->trans('SL3_EnablePropalCardDesc').'</td>';
print '</tr>';
// Supplier Orders (ordersuppliercard)
$enableSupplierOrder = getDolGlobalInt('SUPPLIERLINK3_ENABLE_SUPPLIERORDER', 1);
print '<tr class="oddeven">';
print '<td>'.$langs->trans('SL3_EnableSupplierOrder').'</td>';
print '<td class="center">';
if ($enableSupplierOrder) {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set_enable_supplierorder&token='.newToken().'&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print '</a>';
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set_enable_supplierorder&token='.newToken().'&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a>';
}
print '</td>';
print '<td class="opacitymedium">'.$langs->trans('SL3_EnableSupplierOrderDesc').'</td>';
print '</tr>';
// Stock Replenishment (stockreplenishlist)
$enableReplenish = getDolGlobalInt('SUPPLIERLINK3_ENABLE_REPLENISH', 1);
print '<tr class="oddeven">';
print '<td>'.$langs->trans('SL3_EnableReplenish').'</td>';
print '<td class="center">';
if ($enableReplenish) {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set_enable_replenish&token='.newToken().'&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print '</a>';
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set_enable_replenish&token='.newToken().'&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a>';
}
print '</td>';
print '<td class="opacitymedium">'.$langs->trans('SL3_EnableReplenishDesc').'</td>';
print '</tr>';
// Product Card (productcard)
$enableProductCard = getDolGlobalInt('SUPPLIERLINK3_ENABLE_PRODUCTCARD', 1);
print '<tr class="oddeven">';
print '<td>'.$langs->trans('SL3_EnableProductCard').'</td>';
print '<td class="center">';
if ($enableProductCard) {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set_enable_productcard&token='.newToken().'&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print '</a>';
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set_enable_productcard&token='.newToken().'&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a>';
}
print '</td>';
print '<td class="opacitymedium">'.$langs->trans('SL3_EnableProductCardDesc').'</td>';
print '</tr>';
print '</table>';
print '<br>';
// =============================================================================
// ICON SETTINGS
// =============================================================================
print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="save_icons">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="3">'.$langs->trans('SL3_IconSettings').'</th>';
print '</tr>';
print '<tr class="oddeven">';
print '<td colspan="3" class="opacitymedium">'.$langs->trans('SL3_IconSettingsDesc').'</td>';
print '</tr>';
// Shop Icon
$shopIcon = getDolGlobalString('SUPPLIERLINK3_SHOP_ICON', 'fas fa-store');
print '<tr class="oddeven">';
print '<td width="30%">'.$langs->trans('SL3_ShopIcon').'</td>';
print '<td>';
print '<input type="text" name="shop_icon" value="'.dol_escape_htmltag($shopIcon).'" class="flat minwidth200" placeholder="fas fa-store">';
print ' <span class="sl3-icon-preview" style="font-size: 16px; margin-left: 10px;"><i class="'.$shopIcon.'" style="color: #0077b6;"></i></span>';
print '</td>';
print '<td class="opacitymedium">'.$langs->trans('SL3_ShopIconDesc').'</td>';
print '</tr>';
// Stock Icon (optional, for future use)
$stockIcon = getDolGlobalString('SUPPLIERLINK3_STOCK_ICON', '');
print '<tr class="oddeven">';
print '<td>'.$langs->trans('SL3_StockIcon').'</td>';
print '<td>';
print '<input type="text" name="stock_icon" value="'.dol_escape_htmltag($stockIcon).'" class="flat minwidth200" placeholder="fas fa-box">';
if (!empty($stockIcon)) {
print ' <span class="sl3-icon-preview" style="font-size: 16px; margin-left: 10px;"><i class="'.$stockIcon.'"></i></span>';
}
print '</td>';
print '<td class="opacitymedium">'.$langs->trans('SL3_StockIconDesc').'</td>';
print '</tr>';
// Icon preview row
print '<tr class="oddeven">';
print '<td>'.$langs->trans('SL3_IconPreview').'</td>';
print '<td colspan="2">';
print '<div style="display: flex; gap: 20px; align-items: center; padding: 10px; background: #f9f9f9; border-radius: 4px;">';
// Preview: Shop link with stock badge
print '<div style="display: inline-flex; align-items: center;">';
print '<span style="display: inline-block; width: 28px; text-align: center;">';
print '<a href="#" style="color: #0077b6; font-size: 14px;"><i class="'.$shopIcon.'"></i></a>';
print '</span>';
print '<span style="display: inline-block; min-width: 55px; text-align: right;">';
print '<span class="badge badge-success" style="background-color: #28a745; color: #fff;">42</span>';
print '</span>';
print '</div>';
print '<div style="display: inline-flex; align-items: center;">';
print '<span style="display: inline-block; width: 28px; text-align: center;">';
print '<a href="#" style="color: #0077b6; font-size: 14px;"><i class="'.$shopIcon.'"></i><i class="fas fa-caret-down" style="font-size:8px;margin-left:2px;"></i></a>';
print '</span>';
print '<span style="display: inline-block; min-width: 55px; text-align: right;">';
print '<span class="badge badge-warning" style="background-color: #fd7e14; color: #fff;">8</span>';
print '</span>';
print '</div>';
print '<div style="display: inline-flex; align-items: center;">';
print '<span style="display: inline-block; width: 28px; text-align: center;"></span>';
print '<span style="display: inline-block; min-width: 55px; text-align: right;">';
print '<span class="badge badge-danger" style="background-color: #dc3545; color: #fff;">0</span>';
print '</span>';
print '</div>';
print '</div>';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td colspan="3" class="center">';
print '<input type="submit" class="button button-save" value="'.$langs->trans("Save").'">';
print '</td>';
print '</tr>';
print '</table>';
print '</form>';
print '<br>';
// =============================================================================
// DEBUG SETTINGS
// =============================================================================
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="3">'.$langs->trans('SL3_DebugSettings').'</th>';
print '</tr>';
// Debug-Modus (default: OFF)
$debugMode = getDolGlobalInt('SUPPLIERLINK3_DEBUG_MODE', 0);
print '<tr class="oddeven">';
print '<td>'.$langs->trans('SL3_DebugMode').'</td>';
print '<td class="center" width="80">';
if ($debugMode) {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=setdebug&token='.newToken().'&value=0">';
print img_picto($langs->trans("Activated"), 'switch_on');
print '</a>';
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=setdebug&token='.newToken().'&value=1">';
print img_picto($langs->trans("Disabled"), 'switch_off');
print '</a>';
}
print '</td>';
print '<td class="opacitymedium">'.$langs->trans('SL3_DebugModeDesc').'</td>';
print '</tr>';
// Debug-Log anzeigen
$logFile = '/tmp/supplierlink3_debug.log';
print '<tr class="oddeven">';
print '<td>'.$langs->trans('SL3_DebugLog').'</td>';
print '<td colspan="2">';
if (file_exists($logFile)) {
$logContent = file_get_contents($logFile);
$logSize = filesize($logFile);
print '<strong>'.$langs->trans('SL3_DebugLogFile').':</strong> '.$logFile.' ('.$langs->trans('SL3_DebugLogSize').': '.round($logSize/1024, 2).' KB)<br>';
print '<a class="button" href="'.$_SERVER["PHP_SELF"].'?action=cleardebuglog&token='.newToken().'">'.$langs->trans('SL3_DebugLogClear').'</a>';
print '<br><br>';
print '<strong>'.$langs->trans('SL3_DebugLogLastEntries').':</strong><br>';
print '<textarea readonly style="width:100%; height:200px; font-family:monospace; font-size:11px;">';
// Zeige letzte 100 Zeilen
$lines = explode("\n", $logContent);
$lastLines = array_slice($lines, -100);
print htmlspecialchars(implode("\n", $lastLines));
print '</textarea>';
} else {
print '<span class="opacitymedium">'.$langs->trans('SL3_DebugLogEmpty').'</span>';
}
print '</td>';
print '</tr>';
print '</table>';
print '<br>';
// =============================================================================
// REGISTERED HOOKS
// =============================================================================
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th colspan="3">'.$langs->trans('SL3_RegisteredHooks').'</th>';
print '</tr>';
$hooks = array(
'ordersuppliercard' => $langs->trans('SL3_HookOrderSupplier'),
'ordercard' => $langs->trans('SL3_HookOrderCard'),
'propalcard' => $langs->trans('SL3_HookPropalCard'),
'productcard' => $langs->trans('SL3_HookProductCard'),
'productpricecard' => $langs->trans('SL3_HookProductPrice'),
'stockreplenishlist' => $langs->trans('SL3_HookReplenish'),
);
// Check which hooks are enabled
$enabledHooks = array(
'ordersuppliercard' => getDolGlobalInt('SUPPLIERLINK3_ENABLE_SUPPLIERORDER', 1),
'ordercard' => getDolGlobalInt('SUPPLIERLINK3_ENABLE_ORDERCARD', 1),
'propalcard' => getDolGlobalInt('SUPPLIERLINK3_ENABLE_PROPALCARD', 1),
'productcard' => getDolGlobalInt('SUPPLIERLINK3_ENABLE_PRODUCTCARD', 1),
'productpricecard' => getDolGlobalInt('SUPPLIERLINK3_ENABLE_PRODUCTCARD', 1),
'stockreplenishlist' => getDolGlobalInt('SUPPLIERLINK3_ENABLE_REPLENISH', 1),
);
foreach ($hooks as $hook => $desc) {
$isEnabled = $enabledHooks[$hook] ?? 1;
print '<tr class="oddeven">';
print '<td width="200"><code>'.$hook.'</code></td>';
print '<td>'.$desc.'</td>';
print '<td class="center" width="60">';
if ($isEnabled) {
print '<span class="badge badge-status4">'.$langs->trans("Activated").'</span>';
} else {
print '<td class="center">'."\n";
print '<a href="'.$_SERVER["PHP_SELF"].'?action=set&token='.newToken().'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"), 'switch_off').'</a>';
print "</td>";
}
// Default
print '<td class="center">';
$constforvar = 'SUPPLIERLINK3_'.strtoupper($myTmpObjectKey).'_ADDON_PDF';
if (getDolGlobalString($constforvar) == $name) {
//print img_picto($langs->trans("Default"), 'on');
// Even if choice is the default value, we allow to disable it. Replace this with previous line if you need to disable unset
print '<a href="'.$_SERVER["PHP_SELF"].'?action=unsetdoc&token='.newToken().'&object='.urlencode(strtolower($myTmpObjectKey)).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'&amp;type='.urlencode($type).'" alt="'.$langs->trans("Disable").'">'.img_picto($langs->trans("Enabled"), 'on').'</a>';
} else {
print '<a href="'.$_SERVER["PHP_SELF"].'?action=setdoc&token='.newToken().'&object='.urlencode(strtolower($myTmpObjectKey)).'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"), 'off').'</a>';
print '<span class="badge badge-status8">'.$langs->trans("Disabled").'</span>';
}
print '</td>';
// Info
$htmltooltip = ''.$langs->trans("Name").': '.$module->name;
$htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
if ($module->type == 'pdf') {
$htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
}
$htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
$htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
$htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
$htmltooltip .= '<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
print '<td class="center">';
print $form->textwithpicto('', $htmltooltip, 1, 'info');
print '</td>';
// Preview
print '<td class="center">';
if ($module->type == 'pdf') {
$newname = preg_replace('/_'.preg_quote(strtolower($myTmpObjectKey), '/').'/', '', $name);
print '<a href="'.$_SERVER["PHP_SELF"].'?action=specimen&module='.urlencode($newname).'&object='.urlencode($myTmpObjectKey).'">'.img_object($langs->trans("Preview"), 'pdf').'</a>';
} else {
print img_object($langs->transnoentitiesnoconv("PreviewNotAvailable"), 'generic');
}
print '</td>';
print "</tr>\n";
}
}
}
}
}
}
}
}
print '</table>';
}
print '</tr>';
}
if (empty($setupnotempty)) {
print '<br>'.$langs->trans("NothingToSetup");
}
print '</table>';
// Page end
print dol_get_fiche_end();
// JavaScript for live icon preview
print '<script>
$(document).ready(function() {
$("input[name=\'shop_icon\']").on("input", function() {
var iconClass = $(this).val();
$(this).siblings(".sl3-icon-preview").find("i").attr("class", iconClass);
});
$("input[name=\'stock_icon\']").on("input", function() {
var iconClass = $(this).val();
var $preview = $(this).siblings(".sl3-icon-preview");
if ($preview.length === 0) {
$(this).after(\' <span class="sl3-icon-preview" style="font-size: 16px; margin-left: 10px;"><i class="\' + iconClass + \'"></i></span>\');
} else {
$preview.find("i").attr("class", iconClass);
}
});
});
</script>';
llxFooter();
$db->close();

0
build/buildzip.php Executable file → Normal file
View file

0
build/makepack-supplierlink3.conf Executable file → Normal file
View file

0
img/README.md Executable file → Normal file
View file

91
langs/en_US/supplierlink3.lang Executable file → Normal file
View file

@ -1,42 +1,97 @@
# Translation file
# SupplierLink3 - English translation
# Copyright (C) 2025 Eduard Wisch <data@data-it-solution.de>
#
# Generic
#
# Module label 'ModuleSupplierLink3Name'
ModuleSupplierLink3Name = SupplierLink3
# Module description 'ModuleSupplierLink3Desc'
ModuleSupplierLink3Desc = SupplierLink3 description
ModuleSupplierLink3Desc = Supplier linking with shop links and stock display
#
# Admin page
#
SupplierLink3Setup = SupplierLink3 setup
SupplierLink3Setup = SupplierLink3 Setup
Settings = Settings
SupplierLink3SetupPage = SupplierLink3 setup page
NewSection=New section
SUPPLIERLINK3_MYPARAM1 = My param 1
SUPPLIERLINK3_MYPARAM1Tooltip = My param 1 tooltip
SUPPLIERLINK3_MYPARAM2=My param 2
SUPPLIERLINK3_MYPARAM2Tooltip=My param 2 tooltip
SupplierLink3Description = Displays shop links and stock levels in orders, proposals and supplier orders
# Settings sections
SL3_DisplaySettings = Display Settings
SL3_DisplaySettingsDesc = Choose where shop links and stock levels should be displayed
SL3_IconSettings = Icon Settings
SL3_IconSettingsDesc = Customize the icons used
SL3_DebugSettings = Debug Settings
SL3_RegisteredHooks = Registered Hooks
# Display areas
SL3_EnableOrderCard = Customer Orders
SL3_EnableOrderCardDesc = Show shop links and stock in customer orders
SL3_EnablePropalCard = Proposals
SL3_EnablePropalCardDesc = Show shop links and stock in proposals
SL3_EnableSupplierOrder = Supplier Orders
SL3_EnableSupplierOrderDesc = Show shop links and stock in supplier orders
SL3_EnableReplenish = Stock Replenishment
SL3_EnableReplenishDesc = Show shop links and stock in the replenishment list
SL3_EnableProductCard = Product Card
SL3_EnableProductCardDesc = Show shop links on the product card
# Icons
SL3_ShopIcon = Shop Icon
SL3_ShopIconDesc = FontAwesome class for the shop icon (e.g. fa-store, fa-shopping-cart, fa-external-link-alt)
SL3_StockIcon = Stock Icon
SL3_StockIconDesc = FontAwesome class for the stock icon (e.g. fa-box, fa-warehouse, fa-cubes)
SL3_IconPreview = Preview
# Debug
SL3_DebugMode = Debug Mode
SL3_DebugModeDesc = Writes debug messages to the log file
SL3_DebugLog = Debug Log
SL3_DebugLogFile = Log file
SL3_DebugLogSize = Size
SL3_DebugLogClear = Clear log
SL3_DebugLogCleared = Debug log cleared
SL3_DebugLogEmpty = No log file exists. Enable debug mode and perform an action.
SL3_DebugLogLastEntries = Last entries
# Hooks
SL3_HookOrderSupplier = Supplier Orders - Shop links and stock
SL3_HookOrderCard = Customer Orders - Shop links, stock and "Create supplier order" button
SL3_HookPropalCard = Proposals - Shop links and stock
SL3_HookProductCard = Product Card - Shop links
SL3_HookProductPrice = Product Prices - Shop links
SL3_HookReplenish = Replenishment - Shop links and stock
# Messages
SetupSaved = Settings saved
#
# About page
#
About = About
SupplierLink3About = About SupplierLink3
SupplierLink3AboutPage = SupplierLink3 about page
SupplierLink3AboutPage = SupplierLink3 information
SL3_Version = Version
SL3_Author = Author
SL3_License = License
SL3_Features = Features
SL3_Feature1 = Shop links to supplier webshops
SL3_Feature2 = Stock display with colored badges
SL3_Feature3 = Quick supplier order creation from customer orders
SL3_Feature4 = Multi-supplier support with popup selection
SL3_Documentation = Documentation
#
# Sample page
# Stock badges
#
SupplierLink3Area = Home SupplierLink3
MyPageName = My page name
SL3_StockCritical = Critical (< 1)
SL3_StockWarning = Warning (below minimum stock)
SL3_StockLow = Low (below desired stock)
SL3_StockOk = Sufficient
#
# Sample widget
# Supplier order creation
#
MyWidget = My widget
MyWidgetDescription = My widget description
SL3_CreateSupplierOrder = Create Supplier Order
SL3_SelectSupplier = Select supplier
SL3_SelectProducts = Select products
SL3_NoSuppliers = No suppliers available

0
lib/supplierlink3.lib.php Executable file → Normal file
View file

0
modulebuilder.txt Executable file → Normal file
View file

0
sql/dolibarr_allversions.sql Executable file → Normal file
View file

0
supplierlink3index.php Executable file → Normal file
View file