src/Logging/Activity/InvoiceLog.php line 20

Open in your IDE?
  1. <?php
  2. //----------------------------------------------------------------------
  3. // src/Logging/InvoiceLog.php
  4. //----------------------------------------------------------------------
  5. namespace App\Logging\Activity;
  6. use Doctrine\Persistence\ManagerRegistry;
  7. use App\Entity\Access;
  8. use App\Entity\Platform\Invoice\Invoice;
  9. use App\Entity\Platform\Invoice\InvoiceStatus;
  10. use App\Logging\Tools;
  11. use App\Services\Location\AddressTools;
  12. use App\Services\LogTools;
  13. class InvoiceLog
  14. {
  15.     private array $pendingLogArgs = [];
  16.     public function __construct(ManagerRegistry $doctrineLogTools $logToolsTools $tools)
  17.     {
  18.         $this->em $doctrine->getManager();
  19.         $this->logTools $logTools;
  20.         $this->tools $tools;
  21.     }
  22.     public function logCreation(Invoice $invoice)
  23.     {
  24.         $pendingLogArgs = [];
  25.         //----------------------------------------------------------------------
  26.         // Handle EventListener changes
  27.         $specialLog $this->handleSoldeChanges($invoice);
  28.         if ($specialLog !== null)
  29.         {
  30.             $pendingLogArgs[] = $specialLog;
  31.         }
  32.         //----------------------------------------------------------------------
  33.         //----------------------------------------------------------------------
  34.         // Fetch eventual info stored in the object
  35.         $loggingData $this->logTools->handleLoggingData($invoice);
  36.         $info $loggingData['info'];
  37.         $specialAuthor $loggingData['special_author'];
  38.         $ignore $loggingData['ignore'];
  39.         if ($ignore) return $pendingLogArgs;
  40.         //----------------------------------------------------------------------
  41.         // Init base log args
  42.         // This does not contain action
  43.         $args $this->initArgs($invoice$loggingData);
  44.         //----------------------------------------------------------------------
  45.         $action "invoice_add";
  46.         if ($invoice->isDraft())
  47.         {
  48.             $action "invoice_draft_add";
  49.         }
  50.         if ($invoice->isCredit() || $invoice->isCreditFree())
  51.         {
  52.             $action "invoice_add_credit";
  53.             if ($invoice->isDraft())
  54.             {
  55.                 $action "invoice_credit_draft_add";
  56.             }
  57.         }
  58.         $args["action"] = $action;
  59.         $pendingLogArgs[] = $args;
  60.         return $pendingLogArgs;
  61.     }
  62.     public function logChanges(Invoice $invoice$changes)
  63.     {
  64.         $pendingLogArgs = [];
  65.         //----------------------------------------------------------------------
  66.         // Handle EventListener changes
  67.         $specialLog $this->handleSoldeChanges($invoice);
  68.         if ($specialLog !== null)
  69.         {
  70.             $pendingLogArgs[] = $specialLog;
  71.         }
  72.         //----------------------------------------------------------------------
  73.         //----------------------------------------------------------------------
  74.         // Fetch eventual info stored in the object
  75.         $loggingData $this->logTools->handleLoggingData($invoice);
  76.         $info $loggingData['info'];
  77.         $specialAuthor $loggingData['special_author'];
  78.         $ignore $loggingData['ignore'];
  79.         if ($ignore) return $pendingLogArgs;
  80.         //----------------------------------------------------------------------
  81.         // Init base log args
  82.         // This does not contain action
  83.         $args $this->initArgs($invoice$loggingData);
  84.         //----------------------------------------------------------------------
  85.         // Clear info for special cases
  86.         if ($info == "convert_draft")
  87.         {
  88.             $args["info"] = null;
  89.         }
  90.         $action "invoice_edit";
  91.         if ($invoice->isDraft())
  92.         {
  93.             $action "invoice_draft_edit";
  94.         }
  95.         $basicChanges = array(
  96.             "ref",
  97.             "refOrder",
  98.             "info",
  99.             "internalInfo",
  100.             "mentionInfo",
  101.             "visibleToClient",            // Plan.io Task #4327
  102.             "ikeaSent",
  103.         );
  104.         $labelChanges = array(
  105.             "status",
  106.             "tva",
  107.             "paymentDeadline",
  108.         );
  109.         // This is triggered when we are actually changing
  110.         // the object referenced in Devis :: $interventionAddress
  111.         $addressChanges = array(
  112.             "interventionAddress",
  113.             "billingAddress",
  114.         );
  115.         // Method getLogLabel() should be defined for these objects/entities
  116.         $objectChanges = array(
  117.             "template",
  118.             "emitter",
  119.             "society",
  120.             "manager",
  121.             "author",
  122.         );
  123.         $dateChanges = array(
  124.             "creationDate",
  125.             "paymentDeadlineDate",
  126.         );
  127.         // See what changed and log (members first)
  128.         foreach ($changes as $key => $change)
  129.         {
  130.             // Something to skip ?
  131.             if (strpos($key"total") === || strpos($key"solde") === 0)
  132.             {
  133.                 continue;
  134.             }
  135.             $name $this->logTools->camelToSnakeCase($key);
  136.             $args["action"]    = $action."_".$name;
  137.             $before $change[0];
  138.             $after $change[1];
  139.             if (in_array($key$basicChanges))
  140.             {
  141.                 $args $this->tools->handleBasicChanges($args$before$after);
  142.                 if ($key == "ikeaSent")
  143.                 {
  144.                     $ikeaAction "ikea_service_order_invoice_sent_to_ikea";
  145.                     $args["action"] = $ikeaAction;                    
  146.                     $pendingLogArgs[] = $args;
  147.                     $ikeaArgs $this->tools->handleIkeaServiceOrder($after$invoice$ikeaAction$info$specialAuthor);
  148.                     foreach ($ikeaArgs as $argsItem)
  149.                     {
  150.                         $pendingLogArgs[] = $argsItem;
  151.                     }
  152.                 }
  153.                 else
  154.                 {
  155.                     $pendingLogArgs[] = $args;
  156.                 }
  157.                 continue;
  158.             }
  159.             if (in_array($key$labelChanges))
  160.             {
  161.                 $pendingLogArgs[] = $this->tools->handleLabelChanges($args$before$after);
  162.                 continue;
  163.             }
  164.             if (in_array($key$objectChanges))
  165.             {
  166.                 $pendingLogArgs[] = $this->tools->handleObjectChanges($args$before$after);
  167.                 continue;
  168.             }
  169.             if (in_array($key$addressChanges))
  170.             {
  171.                 $pendingLogArgs[] = $this->tools->handleAddressChanges($args$before$after);
  172.                 continue;
  173.             }
  174.             if (in_array($key$dateChanges))
  175.             {
  176.                 // dateChanges can be null
  177.                 $changeLogs $this->tools->handleDateChanges($args$before$after);
  178.                 if ($changeLogs !== null$pendingLogArgs[] = $changeLogs;
  179.                 continue;
  180.             }
  181.             // Plan.io Task #4326
  182.             // Handle Converting Drafts to Invoices
  183.             if ($key == "draft")
  184.             {
  185.                 if ($info == "convert_draft")
  186.                 {
  187.                     $tempAction "invoice_draft_convert";
  188.                     if ($invoice->isCredit() || $invoice->isCreditFree())
  189.                     {
  190.                         $tempAction "invoice_credit_draft_convert";
  191.                     }
  192.                     $args["action"] = $tempAction;
  193.                     // Old and new values
  194.                     $args["old_value"] = $invoice->getOldRef();
  195.                     $args["new_value"] = $invoice->getRef();
  196.                     $args["info"] = null;
  197.                     $pendingLogArgs[] = $args;
  198.                 }
  199.                 continue;
  200.             }
  201.         }
  202.         if ($invoice->getProducts()->isDirty())
  203.         {
  204.             // Make a copy of product changes
  205.             $this->saveInvoiceProducts($invoice,
  206.                 $invoice->getProducts()->getSnapshot(), $invoice->getProducts());
  207.         }
  208.         // See what changed and log (relationships OneToMany and ManyToMany second)
  209.         if ($invoice->getProducts()->isDirty())
  210.         {
  211.             $old "";
  212.             foreach ($invoice->getProducts()->getSnapshot() as $product)
  213.             {
  214.                 $old .= $product->getRef();
  215.                 $old .= ", ";
  216.             }
  217.             if ($old != "")
  218.             {
  219.                 $old substr($old0, -1);
  220.                 $old substr($old0, -1);
  221.             }
  222.             $new "";
  223.             foreach ($invoice->getProducts() as $product)
  224.             {
  225.                 $new .= $product->getRef();
  226.                 $new .= ", ";
  227.             }
  228.             if ($new != "")
  229.             {
  230.                 $new substr($new0, -1);
  231.                 $new substr($new0, -1);
  232.             }
  233.             $args["action"]        = "invoice_edit_products";
  234.             $args["old_value"]    = $old;
  235.             $args["new_value"]    = $new;
  236.             $pendingLogArgs[] = $args;
  237.         }
  238.         // Invoice :: $interventionAddress and Invoice :: $billingAddress
  239.         // are handled in AddressLog
  240.         // Triggered when the object does not change, but its members do
  241.         return $pendingLogArgs;
  242.     }
  243.     // This only concerns Drafts
  244.     public function logRemoval(Invoice $invoice)
  245.     {
  246.         if ($invoice->isNotDraft())
  247.         {
  248.             return [];
  249.         }
  250.         $pendingLogArgs = [];
  251.         //----------------------------------------------------------------------
  252.         // Fetch eventual info stored in the object
  253.         $loggingData $this->logTools->handleLoggingData($invoice);
  254.         $info $loggingData['info'];
  255.         $specialAuthor $loggingData['special_author'];
  256.         $ignore $loggingData['ignore'];
  257.         if ($ignore) return $pendingLogArgs;
  258.         //----------------------------------------------------------------------
  259.         // Init base log args
  260.         // This does not contain action
  261.         $args $this->initArgs($invoice$loggingData);
  262.         //----------------------------------------------------------------------
  263.         $args["action"] = "invoice_draft_delete";
  264.         $pendingLogArgs[] = $args;
  265.         return $pendingLogArgs;
  266.     }
  267.     public function initArgs(Invoice $invoice$loggingData)
  268.     {
  269.         $receiver $invoice->getReceiver();
  270.         $society $invoice->getSociety();
  271.         $societyGroup $society->getSocietyGroup();
  272.         $mission $invoice->getMission();
  273.         $args = array(
  274.             "object_id"                    =>    $invoice->getId(),
  275.             "object_bundle"                =>    "Platform",
  276.             "object_entity"                =>    "Invoice",
  277.             "object_display"            =>    $invoice->display(),
  278.             "object_client_id"            =>    $receiver !== null $receiver->getId() : null,
  279.             "object_client_display"        =>    $receiver !== null $receiver->getName() : null,
  280.             "object_mission_id"            =>    $mission !== null $mission->getId() : null,
  281.             "object_mission_display"    =>    $mission !== null $mission->getRef() : null,
  282.             
  283.             "society_group"                =>    $societyGroup,
  284.             "society"                    =>    $society,
  285.             "info"                        =>    $loggingData['info'],
  286.             "special_author"            =>    $loggingData['special_author'],
  287.         );
  288.         return $args;
  289.     }
  290.     public function saveInvoiceProducts(Invoice $invoice$oldProducts$newProducts)
  291.     {
  292.         // [id][ref][title][product/discount][description][value][quantity][unit_id][unit_abbrv][totalHT][totalHTDevis][readonly][devisProductId][originalProduct_id][originalProduct_ref]
  293.         if ($invoice === null)
  294.             return null;
  295.         $today = new \DateTime();
  296.         $stamp $today->format("Y_m");
  297.         // ROOT/custom_logs/product_logs/
  298.         $logPath $this->logTools->getProductLogsDir();
  299.         if (!file_exists($logPath))
  300.         {
  301.             if (!mkdir($logPath0775))
  302.             {
  303.                 // Something went bad
  304.                 $this->logTools->errorlog('Could not create folder '.$logPath);
  305.                 return null;
  306.             }
  307.         }
  308.         $logFile $logPath."invoice_products_".$stamp.".log";
  309.         error_log("--------------------------------------------------\n"3$logFile);
  310.         error_log("[".$today->format("Y-m-d H:i:s")."] ".$invoice->getRef()." [".$invoice->getId()."]\n"3$logFile);
  311.         $oldNb count($oldProducts);
  312.         error_log("Old Products : ".$oldNb."\n"3$logFile);
  313.         foreach ($oldProducts as $product)
  314.         {
  315.             error_log($product->getAsString()."\n"3$logFile);
  316.         }
  317.         $newNb count($newProducts);
  318.         error_log("New Products : ".$newNb."\n"3$logFile);
  319.         foreach ($newProducts as $product)
  320.         {
  321.             error_log($product->getAsString()."\n"3$logFile);
  322.         }
  323.         error_log("--------------------------------------------------\n"3$logFile);
  324.     }
  325.     // Changes done in prePersist / preUpdate are not registred in the
  326.     // $changes recorded by the EntityManager
  327.     // So they need to be manually logged
  328.     public function handleSoldeChanges(Invoice $invoice)
  329.     {
  330.         // Store the old value
  331.         $oldValue $invoice->getStatus()->getValue();
  332.         // Handle totals and decide on status change
  333.         $this->handleSolde($invoice);
  334.         // Get the new value
  335.         $newValue $invoice->getStatus()->getValue();
  336.         // ... and decide if any logging is needed
  337.         if ($oldValue == $newValue)
  338.         {
  339.             return null;
  340.         }
  341.         $action "invoice_auto_status_installment";
  342.         $loggingData = array('info' => null'special_author' => null);
  343.         $args $this->initArgs($invoice$loggingData);
  344.         $args["action"]        = $action;
  345.         $args["old_value"]    = $oldValue;
  346.         $args["new_value"]    = $newValue;
  347.         return $args;
  348.     }
  349.     public function handleSolde($invoice)
  350.     {
  351.         // Do nothing is the invoice is annulled
  352.         if ($invoice->isAnnulled())
  353.             return false;
  354.         // Plan.io Task #4326
  355.         if ($invoice->isDraft())
  356.         {
  357.             return false;
  358.         }
  359.         // Just in case compute totals
  360.         $invoice->computeTotals();
  361.         // Case  : Solde is ZERO, but Status is not "Solde"
  362.         if ($invoice->getSolde() == 0.0)
  363.         {
  364.             // Solde is zero
  365.             // If status is "Solde", do nothing
  366.             if ($invoice->isBalanced())
  367.                 return false;
  368.             // Status is not "Solde"
  369.             // Update it
  370.             $balanced $this->em->getRepository(InvoiceStatus::class)
  371.                 ->findOneBy(array(
  372.                     'societyGroup'        =>    $invoice->getSocietyGroup(),
  373.                     'balanced'            =>    1,
  374.                 ));
  375.             if ($balanced !== null)
  376.             {
  377.                 $invoice->setOldStatus($invoice->getStatus());
  378.                 $invoice->setStatus($balanced);
  379.                 return true;
  380.             }
  381.         }
  382.         else
  383.         {
  384.             // Solde is not zero
  385.             // If status is not "Solde", do nothing
  386.             if ($invoice->isBalanced() == false)
  387.                 return false;
  388.             // Status is "Solde"
  389.             // Update it
  390.             if ($invoice->getOldStatus() !== null)
  391.                 $invoice->setStatus($invoice->getOldStatus());
  392.             else
  393.                 $invoice->setStatus($this->decideStatus($invoice));
  394.             return true;
  395.         }
  396.         return false;
  397.     }
  398. }