src/Controller/Paie/HonoraireController.php line 301

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Paie;
  3. use Mpdf\Mpdf;
  4. use App\Entity\Lrib;
  5. use App\Entity\PPiece;
  6. use App\Entity\PDevise;
  7. use App\Entity\PStatut;
  8. use App\Entity\PDossier;
  9. use App\Entity\Pemploye;
  10. use App\Entity\Probleme;
  11. use App\Entity\LContract;
  12. use App\Entity\PPaiement;
  13. use App\Entity\Prubrique;
  14. use App\Entity\Tbulletin;
  15. use App\Entity\PBordereau;
  16. use App\Entity\TbulletinLg;
  17. use App\Entity\PnatureContract;
  18. use App\Entity\TypRemuneration;
  19. use App\Controller\ApiController;
  20. use App\Entity\InjectRemuneration;
  21. use App\Service\CalculPaieService;
  22. use Doctrine\Persistence\ManagerRegistry;
  23. use Symfony\Component\HttpFoundation\Request;
  24. use Symfony\Component\HttpFoundation\Response;
  25. use Symfony\Component\Routing\Annotation\Route;
  26. use Symfony\Component\HttpFoundation\JsonResponse;
  27. use PhpOffice\PhpSpreadsheet\Reader\Xlsx as Reader;
  28. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  29. use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
  30. #[Route('/paie/honoraire')]
  31. class HonoraireController extends AbstractController
  32. {
  33.     private $em;
  34.     private $calculPaieService;
  35.     private $api;
  36.     public function __construct(ManagerRegistry $doctrineCalculPaieService $calculPaieServiceApiController $api)
  37.     {
  38.         $this->em $doctrine->getManager();
  39.         $this->calculPaieService $calculPaieService;
  40.         $this->api $api;
  41.         
  42.     }
  43.     #[Route('/'name'app_paie_honoraire')]
  44.     public function index(Request $request): Response
  45.     {
  46.         $operations $this->api->check($this->getUser(), 'app_paie_honoraire'$this->em$request);
  47.         if(!is_array($operations)) {
  48.             return $this->redirectToRoute('app_site');  
  49.         }elseif(count($operations) == 0) {
  50.             return $this->render('includes/404.html.twig');
  51.         }
  52.         if(!is_array($operations)) {
  53.             return $this->redirectToRoute('app_site');  
  54.         }elseif(count($operations) == 0) {
  55.             return $this->render('includes/404.html.twig');
  56.         }
  57.         $dossiers $this->em->getRepository(PDossier::class)->findBy(['active' => true]);
  58.         $paiements $this->em->getRepository(PPaiement::class)->findBy(['active' => true]);
  59.         $devises $this->em->getRepository(PDevise::class)->findBy(['active' => true]);
  60.         $elementHonoraires $this->em->getRepository(Prubrique::class)->findBy(['honoraire' => true'active' => true]);
  61.         $natures $this->em->getRepository(PnatureContract::class)->findBy(['type' => $this->em->getRepository(TypRemuneration::class)->findBy(['id' => [35]])]);
  62.         return $this->render('paie/honoraire/index.html.twig', [
  63.            'operations' => $operations,
  64.            'natures' => $natures,
  65.            'paiements' => $paiements,
  66.            'dossiers' => $dossiers,
  67.            'devises' => $devises,
  68.            'elementHonoraires' => $elementHonoraires,
  69.         ]);
  70.     }
  71.     #[Route('/app_paie_honoraire_import/{paiement}/{devise}'name'app_paie_honoraire_import'options: ['expose' => true])]
  72.     public function app_paie_honoraire_import(Request $requestPPaiement $paiement,PDevise $devise): Response
  73.     {
  74.         // $dossier = $this->em->getRepository(PDossier::class)->find($request->get('dossier'));
  75.         $reader = new Reader();
  76.         $spreadsheet $reader->load($request->files->get('file'));
  77.         $worksheet $spreadsheet->getActiveSheet();
  78.         $spreadSheetArys $worksheet->toArray();
  79.         unset($spreadSheetArys[0]);
  80.         $array = [];
  81.         $data = [];
  82.         // dd($spreadSheetArys);
  83.         $count 0;
  84.         foreach ($spreadSheetArys as $key => $sheet) {
  85.             $element $this->em->getRepository(Prubrique::class)->findOneBy(['id' => $sheet[11], 'honoraire' => true'active' => true]);
  86.             if(!$element) {
  87.                 return new JsonResponse('Element introuvable à la ligne '.($key 1).' !'500);                
  88.             } 
  89.             $data [$key]['element']=$element->getId();
  90.             $contract $this->em->getRepository(LContract::class)->findOneBy(['id' => $sheet[0],'active' => true]);
  91.             if(!$contract) {
  92.                 return new JsonResponse('Contrat introuvable à la ligne '.($key 1).' !'500);                
  93.             } 
  94.             $data [$key]['dossier']=$contract->getDossier()->getId();
  95.             if(strtolower($contract->getEmploye()->getCin()) != strtolower($sheet[3])) {
  96.                 return new JsonResponse('le contrat n\'appartient pas à ce cin '.($key 1).' !'500);
  97.             }
  98.             $rib $this->em->getRepository(Lrib::class)->findOneBy(['contact_id' => $contract'active' => true]);
  99.             // dd($rib->getCode(), $sheet[4]);
  100.             // if($paiement->getId() == 1 && !preg_match('/^[0-9]{24}$/', $sheet[4])) {
  101.             if($paiement->getId() == && strlen($sheet[4]) < 24 && preg_match('/^[0-9\s]+$/'$sheet[4])) {
  102.                 return new JsonResponse('RIB incorrect à la ligne '.($key 1).' !'500);
  103.             } elseif ($paiement->getId() == && !$rib) {
  104.                 return new JsonResponse('vous n\'avez aucun RIB lié a cette contrat à la ligne '.($key 1).' !'500);
  105.             }
  106.             elseif($paiement->getId() == && $rib->getCode() != $sheet[4]) {
  107.                 return new JsonResponse('Veuillez insérer un RIB lié au même contrat à la ligne '.($key 1).' !'500);
  108.             }
  109.            
  110.             $count++;
  111.             for ($i=5$i 11 $i++) { 
  112.                 if($this->hasMoreThanTwoDecimals($sheet[$i])) {
  113.                     return new JsonResponse('Vous disposez d\'un montant contenant plus de 2 décimales à la ligne '.($key 1).' !'500);
  114.                 }
  115.             }
  116.             $montant preg_replace('/[\p{Z}\s]+/u'''$sheet[5]);
  117.             $montant_mad preg_replace('/[\p{Z}\s]+/u'''$sheet[6]);
  118.             $brute preg_replace('/[\p{Z}\s]+/u'''$sheet[7]);
  119.             $brute_mad preg_replace('/[\p{Z}\s]+/u'''$sheet[8]);
  120.             $ir preg_replace('/[\p{Z}\s]+/u'''$sheet[9]);
  121.             $ir_mad preg_replace('/[\p{Z}\s]+/u'''$sheet[10]);
  122.             $montant str_replace(',''.'$montant);
  123.             $montant_mad str_replace(',''.'$montant_mad);
  124.             $brute str_replace(',''.'$brute);
  125.             $brute_mad str_replace(',''.'$brute_mad);
  126.             $ir str_replace(',''.'$ir);
  127.             $ir_mad str_replace(',''.'$ir_mad);
  128.             
  129.             if($ir or $brute or $montant 0) {
  130.                 return new JsonResponse('Vous un montant négatif à la ligne '.($key 1).' !'500);
  131.             }
  132.             
  133.             
  134.             if(number_format(($brute $ir) - $montant2) != or number_format(($brute_mad $ir_mad) - $montant_mad2) != 0) {
  135.                 return new JsonResponse('Vous un écart à la ligne '.($key 1).' !'500);
  136.             }
  137.             $searchedKey $this->searchKeyByKeys($array'contract_id'$contract->getId(), 'element_id'$element->getId());
  138.             // dump($searchedKey);
  139.             if(!is_null($searchedKey)) {
  140.                 $array[$searchedKey]['montant'] += $montant;
  141.                 $array[$searchedKey]['montant_mad'] += $montant_mad;
  142.                 $array[$searchedKey]['brute'] += $brute;
  143.                 $array[$searchedKey]['brute_mad'] += $brute_mad;
  144.                 $array[$searchedKey]['ir'] += $ir;
  145.                 $array[$searchedKey]['ir_mad'] += $ir_mad;
  146.             } else {
  147.                 array_push($array, [
  148.                     'id' => $count,
  149.                     'nom' => $contract->getEmploye()->getNom(),
  150.                     'nature_contract' => $contract->getPnatureContract()->getId(),
  151.                     'prenom' => $contract->getEmploye()->getPrenom(),
  152.                     'contract_id' => $contract->getId(),
  153.                     'dossier_id' => $contract->getDossier()->getId(),
  154.                     'dossier' => $contract->getDossier()->getAbreviation(),
  155.                     'montant' => $montant,
  156.                     'montant_mad' => $montant_mad,
  157.                     'brute' => $brute,
  158.                     'brute_mad' => $brute_mad,
  159.                     'ir' => $ir,
  160.                     'ir_mad' => $ir_mad,
  161.                     'element_id' => $element->getId(),
  162.                     'element' => $element->getDesignation(),
  163.                     'rib' => $rib $rib->getCode() : '',
  164.                 ]);
  165.             }
  166.         }
  167.         // dd($data);
  168.         $data array_unique(array_map('serialize'$data));
  169.         $data array_map('unserialize'$data);
  170.         $data array_values($data);
  171.         $periode $this->calculPaieService->getPeriode();
  172.         
  173.         foreach($data as $d){
  174.             $existingHonoraires $this->em->getRepository(InjectRemuneration::class)
  175.             ->createQueryBuilder('i')
  176.             ->where('i.active = 1 ')
  177.             ->andWhere('i.type = :type ')
  178.             ->andWhere('i.periode = :periode')
  179.             ->andWhere('i.devise = :devise')
  180.             ->andWhere('i.dossier = :dossier')
  181.             ->andWhere('i.rubrique = :rubrique')
  182.             ->setParameter('type''honoraire')
  183.             ->setParameter('periode'$periode)
  184.             ->setParameter('devise'$devise)
  185.             ->setParameter('dossier'$this->em->getRepository(PDossier::class)->find($d["dossier"]))
  186.             ->setParameter('rubrique'$this->em->getRepository(Prubrique::class)->find($d["element"]))
  187.             ->getQuery()
  188.             ->getResult();
  189.             if($existingHonoraires){
  190.                 return new JsonResponse(['message' => 'Les honoraires pour la rubrique '.$d["element"].' existe déjà pour le dossier '.$d["dossier"].' dans la periode '.$periode->getCode()]);
  191.             }
  192.         }
  193.         return new JsonResponse($array);
  194.     }
  195.     #[Route('/app_paie_honoraire_insert'name'app_paie_honoraire_insert'options: ['expose' => true])]
  196.     public function app_paie_honoraire_insert(Request $request): Response
  197.     {
  198.         $devise $this->em->getRepository(PDevise::class)->find($request->get('devise'));
  199.         $paiement $this->em->getRepository(PPaiement::class)->find($request->get('paiement'));
  200.         $observation $request->get('observation');
  201.         $periode $this->calculPaieService->getPeriode();
  202.         if($periode->IsValider()) {
  203.             return new JsonResponse('Periode est valider !'500, [], JSON_UNESCAPED_UNICODE);
  204.         }
  205.         
  206.         $honoraires json_decode($request->get('honoraires'));
  207.         $returnueIR $this->em->getRepository(Prubrique::class)->find(43);
  208.         $divers $this->em->getRepository(Prubrique::class)->find(68);
  209.         $bordoreauIds = [];
  210.         $data=[];
  211.         $count=0;
  212.         // dd($honoraires);
  213.         foreach($honoraires as $key => $dossierKey) {
  214.             $dossier $this->em->getRepository(PDossier::class)->find($key);
  215.             
  216.             // dd($dossier);
  217.             foreach ($dossierKey as $key => $natureKey) {
  218.                 $bordoreau = new PBordereau;
  219.                 $bordoreau->setPiece($this->em->getRepository(PPiece::class)->find(5));
  220.                 $bordoreau->setDevise($devise);
  221.                 $bordoreau->setStatut(
  222.                     $this->em->getRepository(PStatut::class)->find(1)
  223.                 );
  224.                 $bordoreau->setPeriode($periode);
  225.                 $bordoreau->setType('honoraire');
  226.                 $bordoreau->setPaiement($paiement);
  227.                 $bordoreau->setNatureContract($this->em->getRepository(PnatureContract::class)->find($key));
  228.                 $bordoreau->setUserCreated($this->getUser());
  229.                 $bordoreau->setObservation($observation);
  230.                 $bordoreau->setDossier($dossier);
  231.         
  232.                 $this->em->persist($bordoreau);
  233.                 foreach ($natureKey as $key => $honoraire) {
  234.                     // dd($honoraire);
  235.                     $contract=$this->em->getRepository(LContract::class)->find($honoraire->contract_id);
  236.                     $mtChargeInstitutionelle=0;
  237.                     $mtChargeInstitutionelleMad=0;
  238.                     $salaireBrute2 $honoraire->brute;
  239.                     $salaireBrute2Mad $honoraire->brute_mad;
  240.                     $primeComposationIR0;
  241.                     $primeComposationIRMad0;
  242.                     $ir =0;
  243.                     $irMad=0;
  244.                     $pourcentage=($contract->getPnatureContract()->getTauxIr()/ 100);
  245.                     $bulletin = new Tbulletin();
  246.                     $bulletin->setDossier($dossier);
  247.                     $bulletin->setDevise($devise);
  248.                     $bulletin->setPPiece(
  249.                         $this->em->getRepository(PPiece::class)->find(2)
  250.                     );
  251.                     $bulletin->setPaiement($paiement);
  252.                     $bulletin->setObservation($observation);
  253.                     $bulletin->setBordereau($bordoreau);
  254.                     $bulletin->setContract(
  255.                         $this->em->getRepository(LContract::class)->find($honoraire->contract_id)
  256.                     );
  257.                     $bulletin->setPeriode($periode);
  258.         
  259.                     $this->em->persist($bulletin);
  260.         
  261.                     if($pourcentage != null ) {
  262.                         $chargeInstitutionelle $contract->getPnatureContract()->getAbattement() / 100;
  263.                         
  264.                         $mtChargeInstitutionelleMad=round($honoraire->brute_mad $chargeInstitutionelle2);
  265.                         $mtChargeInstitutionelle=round($honoraire->brute $chargeInstitutionelle2);
  266.                         $salaireBrute2Mad round($honoraire->brute_mad $mtChargeInstitutionelleMad2);
  267.                         $salaireBrute2 =round($honoraire->brute $mtChargeInstitutionelle2);
  268.                         $irMad round$salaireBrute2Mad $pourcentage2);
  269.                         $ir round$salaireBrute2 $pourcentage2);
  270.                         
  271.                         $primeComposationIRMad=round($honoraire->montant_mad-($salaireBrute2Mad $irMad),2);
  272.                         $primeComposationIR=round($honoraire->montant-($salaireBrute2 $ir),2);
  273.                         
  274.                         $bulletinDetChargeInstitutionelle = new TbulletinLg();
  275.                         $bulletinDetChargeInstitutionelle->setBulletin($bulletin);
  276.                         $bulletinDetChargeInstitutionelle->setRubrique($this->em->getRepository(Prubrique::class)->find(97));
  277.                         $bulletinDetChargeInstitutionelle->setSens(-1);
  278.                         $bulletinDetChargeInstitutionelle->setMontant($mtChargeInstitutionelleMad);
  279.                         $bulletinDetChargeInstitutionelle->setMontantDevise($mtChargeInstitutionelle);
  280.             
  281.                         $this->em->persist($bulletinDetChargeInstitutionelle);
  282.                         $bulletinDetPrimeComposationIR = new TbulletinLg();
  283.                         $bulletinDetPrimeComposationIR->setBulletin($bulletin);
  284.                         $bulletinDetPrimeComposationIR->setRubrique($this->em->getRepository(Prubrique::class)->find(98));
  285.                         $bulletinDetPrimeComposationIR->setSens(1);
  286.                         $bulletinDetPrimeComposationIR->setMontant($primeComposationIRMad);
  287.                         $bulletinDetPrimeComposationIR->setMontantDevise($primeComposationIR);
  288.             
  289.                         $this->em->persist($bulletinDetPrimeComposationIR);
  290.                         $bulletinDetRetunueIr = new TbulletinLg();
  291.                         $bulletinDetRetunueIr->setBulletin($bulletin);
  292.                         $bulletinDetRetunueIr->setRubrique($returnueIR);
  293.                         $bulletinDetRetunueIr->setSens(-1);
  294.                         $bulletinDetRetunueIr->setMontant($irMad);
  295.                         $bulletinDetRetunueIr->setMontantDevise($ir);
  296.             
  297.                         $this->em->persist($bulletinDetRetunueIr);
  298.                     }
  299.                     // $netMad=round(($salaireBrute2Mad+$primeComposationIRMad)-$irMad ,2);
  300.                     // $net=round(($salaireBrute2+$primeComposationIR)-$ir ,2);
  301.                     
  302.                     $bulletinDetDivers = new TbulletinLg();
  303.                     $bulletinDetDivers->setBulletin($bulletin);
  304.                     $bulletinDetDivers->setRubrique($divers);
  305.                     $bulletinDetDivers->setSens(1);
  306.                     $bulletinDetDivers->setMontant($honoraire->montant_mad);
  307.                     $bulletinDetDivers->setMontantDevise($honoraire->montant);
  308.                     
  309.                     $this->em->persist($bulletinDetDivers);
  310.                     
  311.                     $bulletinDet = new TbulletinLg();
  312.                     $bulletinDet->setBulletin($bulletin);
  313.                     $bulletinDet->setRubrique($this->em->getRepository(Prubrique::class)->find($honoraire->element_id));
  314.                     $bulletinDet->setSens(1);
  315.                     $bulletinDet->setMontant($honoraire->brute_mad);
  316.                     $bulletinDet->setMontantDevise($honoraire->brute);
  317.                     
  318.                     $this->em->persist($bulletinDet);
  319.                     $bulletinDetBruteImposable = new TbulletinLg();
  320.                     $bulletinDetBruteImposable->setBulletin($bulletin);
  321.                     $bulletinDetBruteImposable->setRubrique($this->em->getRepository(Prubrique::class)->find(95));
  322.                     $bulletinDetBruteImposable->setSens(1);
  323.                     $bulletinDetBruteImposable->setMontant($salaireBrute2Mad);
  324.                     $bulletinDetBruteImposable->setMontantDevise($salaireBrute2);
  325.                     
  326.                     $this->em->persist($bulletinDetBruteImposable);
  327.                     $count++;
  328.                     $data [$count]['dossier']=$dossier->getId();
  329.                     $data [$count]['element']=$honoraire->element_id;
  330.                 }
  331.                 $this->em->flush();
  332.                 array_push($bordoreauIds$bordoreau->getId());
  333.                 
  334.             }          
  335.         }
  336.         
  337.         $data array_unique(array_map('serialize'$data));
  338.         $data array_map('unserialize'$data);
  339.         $data array_values($data);
  340.         // dd($data);
  341.         
  342.         foreach($data as $d){
  343.             $InjectRemuneration = new InjectRemuneration();
  344.             $InjectRemuneration->setDossier$this->em->getRepository(PDossier::class)->find($d["dossier"]));
  345.             $InjectRemuneration->setDevise($devise);
  346.             $InjectRemuneration->setRubrique($this->em->getRepository(Prubrique::class)->find($d["element"]));
  347.             $InjectRemuneration->setPeriode($periode);
  348.             $InjectRemuneration->setActive(1);
  349.             $InjectRemuneration->setType('honoraire');
  350.             $InjectRemuneration->setDesignation($request->get('fileHonoraires'));
  351.     
  352.             $this->em->persist($InjectRemuneration);
  353.         }
  354.       
  355.         $this->em->flush();
  356.         $bordoreauIds array_unique($bordoreauIds);
  357.         if(count($bordoreauIds) > 0) {
  358.             $request->request->add(['bordoreauIds' => json_encode($bordoreauIds)]);
  359.         }
  360.         return new JsonResponse('Bien Enregistrer!');
  361.     }
  362.     #[Route('/app_paie_honoraire_list/{periode}'name'app_paie_honoraire_list'options: ['expose' => true])]
  363.     public function app_paie_honoraire_list(Request $request$periode): Response
  364.     {
  365.        
  366.         $date = new \DateTime($periode);
  367.         $periode $this->calculPaieService->getPeriode($date->format('mY'));
  368.         
  369.         $draw $request->query->get('draw');
  370.         $start $request->query->get('start') ?? 0;
  371.         $length $request->query->get('length') ?? 10;
  372.         $search $request->query->all('search')["value"];
  373.         $orderColumnIndex $request->query->all('order')[0]['column'];
  374.         $orderColumn $request->query->all("columns")[$orderColumnIndex]['name'];
  375.         $orderDir $request->query->all('order')[0]['dir'] ?? 'asc';
  376.         $dossier $request->getSession()->get('dossier');
  377.         $queryBuilder $this->em->createQueryBuilder()
  378.         ->select('b.code as bulletin, b.id as bulletin_id, contract.id as id, contract.code as contract_code, p.nom as nom, p.matricule as matricule , p.prenom')
  379.         ->from(LContract::class, 'contract')
  380.         ->innerJoin('contract.employe''p')
  381.         ->innerJoin('contract.bulletins''b')
  382.         ->innerJoin('b.piece''piece')
  383.         ->Where('contract.dossier = :dossier')
  384.         ->andWhere('b.dossier = :dossier')
  385.         ->andWhere('b.periode = :periode')
  386.         ->andWhere('piece.id = 2')
  387.         ->andWhere('b.active = 1')
  388.         ->setParameter('dossier'$dossier)
  389.         ->setParameter('periode'$periode);
  390.         if (!empty($search)) {
  391.             $queryBuilder->andWhere('(contract.code LIKE :search OR b.code LIKE :search OR p.matricule LIKE :search OR  p.nom LIKE :search OR p.prenom LIKE :search)')
  392.                 ->setParameter('search'"%$search%");
  393.         }
  394.         if (!empty($orderColumn)) {
  395.             $queryBuilder->orderBy("$orderColumn"$orderDir);
  396.         }
  397.         $filteredRecords count($queryBuilder->getQuery()->getResult());
  398.         
  399.         // Paginate results
  400.         $queryBuilder->setFirstResult($start)
  401.             ->setMaxResults($length)
  402.             ->orderBy('b.id''DESC');
  403.         $results $queryBuilder->getQuery()->getResult();
  404.         // dd($results);
  405.         foreach ($results as $key => $contract) {
  406.             // dd('amine');
  407.             // if($contract['id'] == 1301) {
  408.             //     dd($this->em->getRepository(PArretTravailLg::class)->getNombreJoursArret($contract['id'], $periode));
  409.             // }
  410.             $results[$key]['DT_RowId'] = $contract['id'];
  411.             $results[$key]['nombreJourTravails'] = "-";
  412.             $results[$key]['salaire'] = '<p style="text-align: right !important; margin:0 !important">'.number_format($this->em->getRepository(Tbulletin::class)->getNetAPayeByDevise($contract['bulletin_id']), 2',' ' ').'</p>';
  413.             $results[$key]['problemes'] = $this->em->getRepository(Probleme::class)->checkIfTheresProblemes($periode$contract['id']);
  414.         }
  415.         
  416.         // dd($results);
  417.         $totalRecords $this->em->createQueryBuilder()
  418.         ->select('COUNT(d.id)')
  419.         ->from(LContract::class, 'd')
  420.         ->innerJoin('d.bulletins''bulletins')
  421.         ->innerJoin('bulletins.piece''piece')
  422.         ->Where('d.active = 1')
  423.         ->andWhere('bulletins.dossier = :dossier')
  424.         ->andWhere('piece.id = 2')
  425.         ->andWhere('bulletins.periode = :periode')
  426.         ->setParameter('dossier'$dossier)
  427.         ->setParameter('periode'$periode)
  428.         ->getQuery()
  429.         ->getSingleScalarResult();
  430.         return new JsonResponse([
  431.             'draw' => $draw,
  432.             'recordsTotal' => $totalRecords,
  433.             'recordsFiltered' => $filteredRecords,
  434.             'data' => $results,
  435.         ]);
  436.     }
  437.     function hasMoreThanTwoDecimals($number) {
  438.         // Convert the number to a string to handle both integers and floats
  439.         $numberStr strval($number);
  440.     
  441.         // Use a regular expression to check if the number has more than two decimals
  442.         // The pattern matches a dot (decimal point), followed by at most two digits
  443.         return preg_match('/\.\d{3,}/'$numberStr) === 1;
  444.     }
  445.     function searchKeyByKeys($array$key1$value1$key2$value2) {
  446.         foreach ($array as $key => $item) {
  447.             if ($item[$key1] == $value1 && $item[$key2] == $value2) {
  448.                 return $key;
  449.             }
  450.         }
  451.         return null// Return null if not found
  452.     }
  453. }