diff --git a/class/actions_importzugferd.class.php b/class/actions_importzugferd.class.php index 1ebb80e..be77bf8 100644 --- a/class/actions_importzugferd.class.php +++ b/class/actions_importzugferd.class.php @@ -68,6 +68,11 @@ class ActionsImportZugferd */ public $result = array(); + /** + * @var array Results for hooks + */ + public $results = array(); + /** * Constructor * @@ -879,4 +884,73 @@ class ActionsImportZugferd { return $this->parser->getInvoiceData(); } + + /** + * Hook to add dashboard line for new products + * + * @param array $parameters Parameters + * @param object $object Object + * @param string $action Action + * @param HookManager $hookmanager Hook manager + * @return int 0 = OK, >0 = number of errors + */ + public function addOpenElementsDashboardLine($parameters, &$object, &$action, $hookmanager) + { + global $langs, $user; + + if (!$user->hasRight('produit', 'lire')) { + return 0; + } + + require_once DOL_DOCUMENT_ROOT.'/core/class/workboardresponse.class.php'; + $langs->load('importzugferd@importzugferd'); + + $sql = "SELECT COUNT(*) as total FROM " . MAIN_DB_PREFIX . "product"; + $sql .= " WHERE entity IN (" . getEntity('product') . ")"; + $sql .= " AND ref LIKE 'New%'"; + + $resql = $this->db->query($sql); + if ($resql) { + $obj = $this->db->fetch_object($resql); + $count = (int) $obj->total; + + if ($count > 0) { + $response = new WorkboardResponse(); + $response->warning_delay = 0; + $response->label = $langs->trans("NewProductsToReview"); + $response->labelShort = $langs->trans("NewProductsToReview"); + $response->url = dol_buildpath('/importzugferd/new_products.php', 1); + $response->img = img_picto('', 'product'); + $response->nbtodo = $count; + $response->nbtodolate = 0; + + $this->results['importzugferd_newproducts'] = $response; + } + } + + return 0; + } + + /** + * Hook to add dashboard group for new products + * + * @param array $parameters Parameters + * @param object $object Object + * @param string $action Action + * @param HookManager $hookmanager Hook manager + * @return int 0 = OK, >0 = number of errors + */ + public function addOpenElementsDashboardGroup($parameters, &$object, &$action, $hookmanager) + { + global $langs; + + $langs->load('importzugferd@importzugferd'); + + $this->results['importzugferd_newproducts'] = array( + 'groupName' => $langs->trans("NewProductsToReview"), + 'stats' => array('importzugferd_newproducts'), + ); + + return 0; + } } diff --git a/core/boxes/box_new_products.php b/core/boxes/box_new_products.php new file mode 100644 index 0000000..37f82ed --- /dev/null +++ b/core/boxes/box_new_products.php @@ -0,0 +1,98 @@ +db = $db; + } + + public function loadBox($max = 5) + { + global $langs; + + $langs->load('importzugferd@importzugferd'); + + // Auf Produktseite alle Einträge zeigen + if (strpos($_SERVER['PHP_SELF'], '/product/index.php') !== false) { + $max = 0; // 0 = kein Limit + } + + include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; + $productstatic = new Product($this->db); + + // Anzahl zählen + $sql = "SELECT COUNT(*) as total FROM ".MAIN_DB_PREFIX."product WHERE ref LIKE 'New%'"; + $resql = $this->db->query($sql); + $total = 0; + if ($resql) { + $obj = $this->db->fetch_object($resql); + $total = $obj->total; + } + + $this->info_box_head = array( + 'text' => $langs->trans("BoxNewProductsToReview").' '.$total.'', + 'sublink' => dol_buildpath('/importzugferd/new_products.php', 1), + 'subtext' => $langs->trans("ShowAll"), + 'subpicto' => 'object_product', + ); + + // Produkte laden + $sql = "SELECT rowid, ref, label, datec FROM ".MAIN_DB_PREFIX."product"; + $sql .= " WHERE ref LIKE 'New%'"; + $sql .= " ORDER BY datec DESC"; + if ($max > 0) { + $sql .= " LIMIT ".((int) $max); + } + + $result = $this->db->query($sql); + if ($result) { + $num = $this->db->num_rows($result); + $line = 0; + + while ($line < $num) { + $objp = $this->db->fetch_object($result); + + $productstatic->id = $objp->rowid; + $productstatic->ref = $objp->ref; + $productstatic->label = $objp->label; + + $this->info_box_contents[$line][] = array( + 'td' => 'class="tdoverflowmax150"', + 'text' => $productstatic->getNomUrl(1), + 'asis' => 1, + ); + + $this->info_box_contents[$line][] = array( + 'td' => 'class="tdoverflowmax150"', + 'text' => $objp->label, + ); + + $this->info_box_contents[$line][] = array( + 'td' => 'class="right"', + 'text' => dol_print_date($this->db->jdate($objp->datec), 'day'), + ); + + $line++; + } + + if ($num == 0) { + $this->info_box_contents[0][0] = array( + 'td' => 'class="center"', + 'text' => $langs->trans("NoNewProductsToReview"), + ); + } + } + } + + public function showBox($head = null, $contents = null, $nooutput = 0) + { + return parent::showBox($this->info_box_head, $this->info_box_contents, $nooutput); + } +} diff --git a/css/importzugferd.css.php b/css/importzugferd.css.php new file mode 100644 index 0000000..1e4a11b --- /dev/null +++ b/css/importzugferd.css.php @@ -0,0 +1,48 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + */ + +/** + * \file css/importzugferd.css.php + * \ingroup importzugferd + * \brief CSS file for importzugferd module + */ + +// Load Dolibarr environment +if (!defined('NOREQUIRESOC')) { + define('NOREQUIRESOC', '1'); +} +if (!defined('NOTOKENRENEWAL')) { + define('NOTOKENRENEWAL', '1'); +} +if (!defined('NOLOGIN')) { + define('NOLOGIN', '1'); +} +if (!defined('NOREQUIREHTML')) { + define('NOREQUIREHTML', '1'); +} +if (!defined('NOREQUIREAJAX')) { + define('NOREQUIREAJAX', '1'); +} + +session_cache_limiter('public'); + +require_once '../../../main.inc.php'; + +header('Content-Type: text/css'); + +?> +/* Icon for importzugferd new products dashboard box */ +.fa-dol-importzugferd_newproducts:before { + content: "\f1b3"; /* FontAwesome cubes icon for products */ +} + +/* Background color for the dashboard box */ +.bg-infobox-importzugferd_newproducts { + background: linear-gradient(135deg, #6c5ce7 0%, #a29bfe 100%) !important; +} diff --git a/new_products.php b/new_products.php new file mode 100644 index 0000000..4bfd86c --- /dev/null +++ b/new_products.php @@ -0,0 +1,291 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/** + * \file new_products.php + * \ingroup importzugferd + * \brief List of products starting with "New" that need review after import + */ + +// Load Dolibarr environment +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; + +// Load translation files +$langs->loadLangs(array('products', 'stocks', 'importzugferd@importzugferd')); + +// Security check +if (!$user->hasRight('produit', 'lire')) { + accessforbidden(); +} + +// Get parameters +$action = GETPOST('action', 'aZ09'); +$massaction = GETPOST('massaction', 'alpha'); +$confirm = GETPOST('confirm', 'alpha'); +$toselect = GETPOST('toselect', 'array'); +$optioncss = GETPOST('optioncss', 'alpha'); + +// Search Criteria +$search_ref = GETPOST("search_ref", 'alpha'); +$search_label = GETPOST("search_label", 'alpha'); +$search_tosell = GETPOST("search_tosell"); +$search_tobuy = GETPOST("search_tobuy"); + +// Load variable for pagination +$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit; +$sortfield = GETPOST('sortfield', 'aZ09comma'); +$sortorder = GETPOST('sortorder', 'aZ09comma'); +$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page"); +if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + $page = 0; +} +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (!$sortfield) { + $sortfield = "p.datec"; +} +if (!$sortorder) { + $sortorder = "DESC"; +} + +// Initialize objects +$object = new Product($db); +$form = new Form($db); + +$arrayfields = array( + 'p.ref' => array('label' => 'Ref', 'checked' => 1, 'position' => 10), + 'p.label' => array('label' => 'Label', 'checked' => 1, 'position' => 20), + 'p.fk_product_type' => array('label' => 'Type', 'checked' => 1, 'position' => 30), + 'p.price' => array('label' => 'SellingPrice', 'checked' => 1, 'position' => 40), + 'p.price_ttc' => array('label' => 'SellingPriceTTC', 'checked' => 0, 'position' => 41), + 'p.tosell' => array('label' => 'OnSell', 'checked' => 1, 'position' => 50), + 'p.tobuy' => array('label' => 'OnBuy', 'checked' => 1, 'position' => 60), + 'p.datec' => array('label' => 'DateCreation', 'checked' => 1, 'position' => 70), +); + +/* + * Actions + */ + +if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { + $search_ref = ''; + $search_label = ''; + $search_tosell = ''; + $search_tobuy = ''; + $toselect = array(); + $search_array_options = array(); +} + +/* + * View + */ + +$title = $langs->trans('NewProductsToReview'); +$help_url = ''; + +llxHeader('', $title, $help_url); + +// Build SQL query +$sql = "SELECT p.rowid, p.ref, p.label, p.fk_product_type, p.entity,"; +$sql .= " p.price, p.price_ttc, p.price_base_type, p.tva_tx,"; +$sql .= " p.tosell, p.tobuy, p.datec, p.tms"; +$sql .= " FROM ".MAIN_DB_PREFIX."product as p"; +$sql .= " WHERE p.entity IN (".getEntity('product').")"; +$sql .= " AND p.ref LIKE 'New%'"; + +// Add search filters +if ($search_ref) { + $sql .= natural_search('p.ref', $search_ref); +} +if ($search_label) { + $sql .= natural_search('p.label', $search_label); +} +if ($search_tosell != '' && $search_tosell >= 0) { + $sql .= " AND p.tosell = ".((int) $search_tosell); +} +if ($search_tobuy != '' && $search_tobuy >= 0) { + $sql .= " AND p.tobuy = ".((int) $search_tobuy); +} + +// Count total +$sqlcount = preg_replace('/^SELECT[^F]*FROM/', 'SELECT COUNT(*) as nbtotalofrecords FROM', $sql); +$sqlcount = preg_replace('/ORDER BY.*$/', '', $sqlcount); +$resqlcount = $db->query($sqlcount); +$nbtotalofrecords = 0; +if ($resqlcount) { + $objcount = $db->fetch_object($resqlcount); + $nbtotalofrecords = $objcount->nbtotalofrecords; +} + +// Add sorting +$sql .= $db->order($sortfield, $sortorder); +$sql .= $db->plimit($limit + 1, $offset); + +$resql = $db->query($sql); +if (!$resql) { + dol_print_error($db); + exit; +} + +$num = $db->num_rows($resql); + +$param = ''; +if ($search_ref) { + $param .= '&search_ref='.urlencode($search_ref); +} +if ($search_label) { + $param .= '&search_label='.urlencode($search_label); +} +if ($search_tosell != '') { + $param .= '&search_tosell='.urlencode($search_tosell); +} +if ($search_tobuy != '') { + $param .= '&search_tobuy='.urlencode($search_tobuy); +} +if ($limit > 0 && $limit != $conf->liste_limit) { + $param .= '&limit='.((int) $limit); +} + +// List header +print '
'; +print ''; +print ''; +print ''; +print ''; + +print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'product', 0, '', '', $limit, 0, 0, 1); + +// Info box +print '
'; +print $langs->trans('NewProductsToReviewDesc', 'New'); +print '

'; + +print '
'; +print ''; + +// Header row with search fields +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; + +// Column headers +print ''; +print_liste_field_titre('Ref', $_SERVER["PHP_SELF"], 'p.ref', '', $param, '', $sortfield, $sortorder); +print_liste_field_titre('Label', $_SERVER["PHP_SELF"], 'p.label', '', $param, '', $sortfield, $sortorder); +print_liste_field_titre('Type', $_SERVER["PHP_SELF"], 'p.fk_product_type', '', $param, '', $sortfield, $sortorder); +print_liste_field_titre('SellingPrice', $_SERVER["PHP_SELF"], 'p.price', '', $param, '', $sortfield, $sortorder, 'right '); +print_liste_field_titre('OnSell', $_SERVER["PHP_SELF"], 'p.tosell', '', $param, '', $sortfield, $sortorder, 'center '); +print_liste_field_titre('OnBuy', $_SERVER["PHP_SELF"], 'p.tobuy', '', $param, '', $sortfield, $sortorder, 'center '); +print_liste_field_titre('DateCreation', $_SERVER["PHP_SELF"], 'p.datec', '', $param, '', $sortfield, $sortorder, 'center '); +print_liste_field_titre('', $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'center '); +print ''; + +// Data rows +$i = 0; +while ($i < min($num, $limit)) { + $obj = $db->fetch_object($resql); + if (!$obj) { + break; + } + + $product_static = new Product($db); + $product_static->id = $obj->rowid; + $product_static->ref = $obj->ref; + $product_static->label = $obj->label; + $product_static->type = $obj->fk_product_type; + $product_static->entity = $obj->entity; + $product_static->status = $obj->tosell; + $product_static->status_buy = $obj->tobuy; + + print ''; + + // Ref + print ''; + + // Label + print ''; + + // Type + print ''; + + // Price + print ''; + + // On sell + print ''; + + // On buy + print ''; + + // Date creation + print ''; + + // Action column + print ''; + + print ''; + $i++; +} + +if ($num == 0) { + print ''; +} + +print '
'.$form->selectyesno('search_tosell', $search_tosell, 1, false, 1, 1).''.$form->selectyesno('search_tobuy', $search_tobuy, 1, false, 1, 1).''; +print ''; +print ''; +print '
'; + print $product_static->getNomUrl(1); + print ''.dol_escape_htmltag($obj->label).''; + if ($obj->fk_product_type == 0) { + print $langs->trans('Product'); + } else { + print $langs->trans('Service'); + } + print ''; + if ($obj->price_base_type == 'TTC') { + print ''.price($obj->price_ttc).''; + } else { + print ''.price($obj->price).''; + } + print ''; + print $product_static->LibStatut($obj->tosell, 5, 0); + print ''; + print $product_static->LibStatut($obj->tobuy, 5, 1); + print ''; + print dol_print_date($db->jdate($obj->datec), 'dayhour'); + print ''; + print ''; + print img_picto($langs->trans('Edit'), 'edit'); + print ''; + print '
'.$langs->trans("NoRecordFound").'
'; +print '
'; +print '
'; + +// End of page +llxFooter(); +$db->close();