diff --git a/htdocs/couffignal/FactureTools.php b/htdocs/couffignal/FactureTools.php index d6f0f1fa9bdeb..a367788e388d0 100644 --- a/htdocs/couffignal/FactureTools.php +++ b/htdocs/couffignal/FactureTools.php @@ -15,9 +15,10 @@ class FactureTools * * @param DoliDB $db Database handler * @param Facture $facture Invoice object + * @param bool $load_obj Load and return object in response if True * @return array List of orders with their client reference and total HT */ - public static function getTotalHtOrdersLinkedToInvoice(DoliDB $db, Facture $invoice): array + public static function getTotalHtOrdersLinkedToInvoice(DoliDB $db, Facture $invoice, bool $load_obj = False): array { $invoice->fetchObjectLinked(); @@ -34,6 +35,9 @@ public static function getTotalHtOrdersLinkedToInvoice(DoliDB $db, Facture $invo } } $orders = CommandeTools::sortOrdersByDateAndRef($orders); + if ($load_obj) { + return array_map(static fn ($o) => ['ref_client' => $o->ref_ext . '(' .$o->ref.')', 'total_ht' => $o->total_ht, 'obj' => $o], $orders); + } return array_map(static fn ($o) => ['ref_client' => $o->ref_ext . '(' .$o->ref.')', 'total_ht' => $o->total_ht], $orders); } diff --git a/htdocs/couffignal/ProjectNodeView.php b/htdocs/couffignal/ProjectNodeView.php new file mode 100644 index 0000000000000..dcaf88aa701cd --- /dev/null +++ b/htdocs/couffignal/ProjectNodeView.php @@ -0,0 +1,225 @@ + [ + 'custom_ref_attr' => 'ref_client', + 'color' => '#65953d', + 'link' => '/commande/card.php?id=' + ], + 'Facture' => [ + 'custom_ref_attr' => 'ref_client', + 'color' => '#a23121', + 'link' => '/compta/facture/card.php?facid=' + ], + 'CommandeFournisseur' => [ + 'custom_ref_attr' => 'ref_supplier', + 'color' => '#599caf', + 'link' => '/fourn/commande/card.php?id=' + ], + 'FactureFournisseur' => [ + 'custom_ref_attr' => 'ref_supplier', + 'color' => '#6059af', + 'link' => '/fourn/facture/card.php?facid=', + ] + ]; + + /** + * Get the seeds - the starting point of the invoicing cycles - present in the project + * + * @param DoliDB $db + * @param Project $project Project object for which we search seeds + * @param array $properties Properties for get_element_list + * @param string $dates Forwarded + * @param string $datee Forwarded + * + * @return array List of Invoices (Facture) + */ + public static function getCycleSeeds(DoliDB $db, Project $project, array $properties, string $dates, string $datee): array + { + // Collect all invoices + $list_invoices = $project->get_element_list('invoice', $properties['table'], $properties['datefieldname'], $dates, $datee, 'fk_projet'); + + // Assume only one serie of invoices + $seeds = []; + foreach ($list_invoices as $k => $id) { + $inv = new Facture($db); + $inv->fetch($id); + if ($inv->is_first()) { + // To support + $inv->fetchPreviousNextSituationInvoice(); + $seeds[] = $inv; + } + } + + return $seeds; + } + + + /** + * Load a Node from its representing object + * + * @param Object Facture|FactureFournisseur|Commande|CommandeFournisseur $obj + * + * @return array Array representing a node + */ + public static function loadNode(Facture|FactureFournisseur|Commande|CommandeFournisseur $obj): array + { + if (array_key_exists(get_class($obj), self::MANAGED_ELEMENTS)) { + $k = get_class($obj); + $custom_ref_attr = self::MANAGED_ELEMENTS[$k]['custom_ref_attr']; + return [ + 'id' => $obj->ref, + 'label' => $obj->ref . ' - ' . $obj->$custom_ref_attr, + 'obj' => $obj, + 'type' => $k, + 'link' => self::MANAGED_ELEMENTS[$k]['link'].$obj->id, + 'tooltip' => $obj->getNomUrl(1), + ]; + } + return []; + } + + + /** + * Load Invoices nodes related to an invoicing cycle + * + * @param array $seed List of nodes representing the FactureFournisseur related to invoicing cycle + * @param array $links Links object for the graph + * * + * @return array List of Invoices nodes (Facture) + */ + public static function loadInvoicesNodes(Facture $seed, array &$links): array + { + // Initialize invoice nodes with invoices + $inv_nodes = []; + foreach (array_merge([$seed], $seed->tab_next_situation_invoice) as $inv) { + $inv_nodes[$inv->ref] = self::loadNode($inv); + } + + // Initialize links between nodes + $keys = array_keys($inv_nodes); + foreach ($keys as $index => $key) { + // Check if there is a next key to avoid out-of-bounds + if (isset($keys[$index + 1])) { + $links[] = [ + 'from' => $inv_nodes[$key]['id'], + 'to' => $inv_nodes[$keys[$index + 1]]['id'] + ]; + } + } + + return $inv_nodes; + } + + + /** + * Load Orders nodes for all invoice nodes of a cycle + * + * @param array $inv_nodes List of nodes representing the Factures in invoicing cycle + * @param array $links Links object for the graph + * + * @return array List of Orders nodes (Commande) + */ + public static function loadOrdersNodes(DoliDB $db, array $inv_nodes, array &$links): array + { + $order_nodes = []; + foreach ($inv_nodes as $i => $node) { + $orders = FactureTools::getTotalHtOrdersLinkedToInvoice($db, $node['obj'], True); + // Add new nodes + foreach ($orders as $o) { + $order_nodes[$o['obj']->ref] = self::loadNode($o['obj']); + // Create links + $o['obj']->fetchObjectLinked(); + foreach ($o['obj']->linkedObjects['facture'] as $id => $facture) { + $links[] = [ + 'from' => $o['obj']->ref, + 'to' => $facture->ref + ]; + } + } + } + + return $order_nodes; + } + + + /** + * Load Supplier Invoices nodes for all invoice nodes of a cycle + * + * @param array $inv_nodes List of nodes representing the Factures in invoicing cycle + * @param array $links Links object for the graph + * + * @return array List of Supplier Invoices nodes (FactureFournisseur) + */ + public static function loadSupplierInvoicesNodes(DoliDB $db, array $inv_nodes, array &$links): array + { + $su_inv_nodes = []; + foreach ($inv_nodes as $i => $node) { + $obj = new LinkClientPayFourn($db); + $su_invs = $obj->getLinkedObjects($node['obj'], $db); + + // Add new nodes + foreach ($su_invs as $su_i) { + $su_inv_nodes[$su_i->ref] = self::loadNode($su_i); + // Create links + $links[] = [ + 'from' => $node['id'], + 'to' => $su_i->ref + ]; + } + } + + return $su_inv_nodes; + } + + + /** + * Load Supplier Orders nodes for all supplier invoice nodes related to an invoicing cycle + * + * @param array $su_inv_nodes List of nodes representing the FactureFournisseur related to invoicing cycle + * @param array $links Links object for the graph + * + * @return array List of Supplier Orders nodes (Commande) + */ + public static function loadSupplierOrdersNodes(array $su_inv_nodes, array &$links): array + { + $su_order_nodes = []; + foreach ($su_inv_nodes as $i => $node) { + $su_orders = FactureFournisseurTools::getOrdersValidatedFromFacturesFourn([$node['obj']]); + // Add new nodes + foreach ($su_orders as $o) { + $su_order_nodes[$o->ref] = self::loadNode($o); + // Create links + $o->fetchObjectLinked(); + foreach ($o->linkedObjects['invoice_supplier'] as $id => $su_inv) { + $links[] = [ + 'from' => $o->ref, + 'to' => $su_inv->ref + ]; + } + } + } + + return $su_order_nodes; + } + +} \ No newline at end of file diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index 09b5642fa01e1..1a0d660390d15 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -721,8 +721,6 @@ $elementuser = new User($db); - - $showdatefilter = 0; // Show the filter on date on top of element list if (!$showdatefilter) { @@ -747,6 +745,237 @@ } +// COUFFIGNAL ADD-ON +// Sample data: nodes and links arrays +require_once DOL_DOCUMENT_ROOT.'/couffignal/ProjectNodeView.php'; +// Utils +$filterExcludeKeys = fn($arr) => array_diff_key($arr, array_flip(['obj'])); + +$seeds = ProjectNodeView::getCycleSeeds($db, $object, $listofreferent['invoice'], $dates, $datee); + +$nodes = []; +$links = []; +foreach ($seeds as $seed) { + // Initialize invoice nodes and links + $inv_nodes = ProjectNodeView::loadInvoicesNodes($seed, $links); + + // Add Orders nodes + $order_nodes = ProjectNodeView::loadOrdersNodes($db, $inv_nodes, $links); + + // Add Supplier_invoices + $su_inv_nodes = ProjectNodeView::loadSupplierInvoicesNodes($db, $inv_nodes, $links); + + // Add Supplier_orders + $su_order_nodes = ProjectNodeView::loadSupplierOrdersNodes($su_inv_nodes, $links); + + // Concat nodes + $nodes = array_merge($nodes, $inv_nodes, $order_nodes, $su_inv_nodes, $su_order_nodes); +} + +// Missing : Refacto +$unlinked_nodes = []; +foreach ($listofreferent as $key => $properties) { + if (in_array($properties['class'], array_keys(ProjectNodeView::MANAGED_ELEMENTS))) { + $list_ids = $object->get_element_list($key, $properties['table'], $properties['datefieldname'], $dates, $datee, 'fk_projet'); + foreach ($list_ids as $k => $id) { + $obj = new $properties['class']($db); + $obj->fetch($id); + $unlinked_nodes[] = ProjectNodeView::loadNode($obj); + } + } +} + +// Concat & clean nodes +$nodes = array_merge($nodes, $unlinked_nodes); +$nodes_wo_obj = array_map($filterExcludeKeys, array_values($nodes)); +$clean_unique_nodes = array_map("unserialize", array_unique(array_map("serialize", $nodes_wo_obj))); + +// Clean links +$links = array_map("unserialize", array_unique(array_map("serialize", $links))); + +// Encode data as JSON for JS +$nodesJson = json_encode(array_values($clean_unique_nodes)); +$linksJson = json_encode(array_values($links)); +$colorJson = json_encode(array_combine(array_keys(ProjectNodeView::MANAGED_ELEMENTS), array_map(fn($v) => $v['color'], ProjectNodeView::MANAGED_ELEMENTS))); +?> + + + + + +

trans('GraphVisualizationTitle');?>

+
+ +
+ + + +