src/ApplicationBundle/Controller/DashboardController.php line 4254

Open in your IDE?
  1. <?php
  2. namespace ApplicationBundle\Controller;
  3. use ApplicationBundle\Constants\GeneralConstant;
  4. use ApplicationBundle\Constants\HumanResourceConstant;
  5. use ApplicationBundle\Entity\DashboardWidget;
  6. use ApplicationBundle\Entity\Employee;
  7. use ApplicationBundle\Entity\EmployeeDetails;
  8. use ApplicationBundle\Entity\SysUser;
  9. use ApplicationBundle\Interfaces\SessionCheckInterface;
  10. use ApplicationBundle\Modules\Accounts\Accounts;
  11. use ApplicationBundle\Modules\Authentication\Constants\UserConstants; use ApplicationBundle\Modules\Api\Constants\ApiConstants;
  12. use ApplicationBundle\Modules\HumanResource\HumanResource;
  13. use ApplicationBundle\Modules\Inventory\Inventory;
  14. use ApplicationBundle\Modules\Purchase\Supplier;
  15. use ApplicationBundle\Modules\Sales\Client;
  16. use ApplicationBundle\Modules\System\Support\PeriodFilterCore;
  17. use ApplicationBundle\Modules\System\MiscActions;
  18. use ApplicationBundle\Modules\System\System;
  19. use ApplicationBundle\Modules\User\Company;
  20. use ApplicationBundle\Modules\User\Position;
  21. use ApplicationBundle\Modules\User\Users;
  22. use CompanyGroupBundle\Entity\CompanyGroup;
  23. use CompanyGroupBundle\Entity\EntityApplicantApplicationList;
  24. use CompanyGroupBundle\Entity\EntityApplicantDetails;
  25. use CompanyGroupBundle\Entity\EntityTicket;
  26. use Symfony\Component\BrowserKit\Client as BrowserClientKit;
  27. use Symfony\Component\Debug\Exception\FlattenException;
  28. use Symfony\Component\HttpFoundation\JsonResponse;
  29. use Symfony\Component\HttpFoundation\Request;
  30. use Symfony\Component\HttpFoundation\Response;
  31. use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
  32. use Symfony\Component\Routing\Generator\UrlGenerator;
  33. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  34. class DashboardController extends GenericController implements SessionCheckInterface
  35. {
  36.     private function getPublicDocumentEntityManager($appId)
  37.     {
  38.         $emGoc $this->getDoctrine()->getManager('company_group');
  39.         $emGoc->getConnection()->connect();
  40.         $goc $emGoc
  41.             ->getRepository("CompanyGroupBundle\\Entity\\CompanyGroup")
  42.             ->findOneBy(
  43.                 array(
  44.                     'appId' => $appId
  45.                 )
  46.             );
  47.         if (!$goc) {
  48.             return array(nullnull);
  49.         }
  50.         $connector $this->container->get('application_connector');
  51.         $connector->resetConnection(
  52.             'default',
  53.             $goc->getDbName(),
  54.             $goc->getDbUser(),
  55.             $goc->getDbPass(),
  56.             $goc->getDbHost(),
  57.             $reset true
  58.         );
  59.         return array($this->getDoctrine()->getManager(), $goc);
  60.     }
  61.     private function buildAllocationAwareTransactionSourceSql(array $filters = [])
  62.     {
  63.         $conn $this->getDoctrine()->getManager()->getConnection();
  64.         $conditions = [];
  65.         if (!empty($filters['document_type'])) {
  66.             $conditions[] = 't.document_type = ' . (int) $filters['document_type'];
  67.         }
  68.         if (!empty($filters['company_id'])) {
  69.             $conditions[] = 't.company_id = ' . (int) $filters['company_id'];
  70.         }
  71.         if (!empty($filters['start_date'])) {
  72.             $conditions[] = "t.ledger_hit_date >= " $conn->quote(date('Y-m-d'strtotime((string) $filters['start_date'])) . ' 00:00:00');
  73.         }
  74.         if (!empty($filters['end_date'])) {
  75.             $conditions[] = "t.ledger_hit_date <= " $conn->quote(date('Y-m-d'strtotime((string) $filters['end_date'])) . ' 23:59:59.999');
  76.         }
  77.         if (!empty($filters['client_head_ids'])) {
  78.             $conditions[] = 'td.accounts_head_id IN (' implode(','array_map('intval', (array) $filters['client_head_ids'])) . ')';
  79.         }
  80.         if (isset($filters['approved'])) {
  81.             $conditions[] = 't.approved = ' . (int) $filters['approved'];
  82.         } else {
  83.             $conditions[] = 't.approved = 1';
  84.         }
  85.         if (isset($filters['ledger_hit'])) {
  86.             $conditions[] = 't.ledger_hit = ' . (int) $filters['ledger_hit'];
  87.         } else {
  88.             $conditions[] = 't.ledger_hit = 1';
  89.         }
  90.         $whereSql = empty($conditions) ? '1=1' implode(' AND '$conditions);
  91.         return "(
  92.             SELECT td.transaction_details_id AS transaction_details_id,
  93.                    td.transaction_id,
  94.                    td.accounts_head_id,
  95.                    td.position,
  96.                    td.amount AS allocation_amount,
  97.                    td.ledger_hit_date,
  98.                    t.document_hash,
  99.                    t.company_id,
  100.                    t.document_type,
  101.                    1 AS has_allocation
  102.             FROM acc_transaction_details td
  103.             JOIN acc_transactions t ON t.transaction_id = td.transaction_id
  104.             JOIN transaction_detail_allocations tda ON tda.transaction_detail_id = td.transaction_details_id
  105.             WHERE " $whereSql "
  106.             UNION ALL
  107.             SELECT td.transaction_details_id AS transaction_details_id,
  108.                    td.transaction_id,
  109.                    td.accounts_head_id,
  110.                    td.position,
  111.                    td.amount AS allocation_amount,
  112.                    td.ledger_hit_date,
  113.                    t.document_hash,
  114.                    t.company_id,
  115.                    t.document_type,
  116.                    0 AS has_allocation
  117.             FROM acc_transaction_details td
  118.             JOIN acc_transactions t ON t.transaction_id = td.transaction_id
  119.             WHERE " $whereSql "
  120.               AND NOT EXISTS (
  121.                   SELECT 1
  122.                   FROM transaction_detail_allocations tda
  123.                   WHERE tda.transaction_detail_id = td.transaction_details_id
  124.               )
  125.         )";
  126.     }
  127.     public function doLoginAsAction(Request $request)
  128.     {
  129.         $session $request->getSession();
  130.         if ($request->isMethod('POST')) {
  131.             $session->set(UserConstants::USER_CURRENT_POSITION$request->request->get('position'));
  132.             $curr_position_id $request->request->get('position');
  133.             if ($session->get(UserConstants::USER_LOGIN_ID) != 0) {
  134.                 $loginID $this->get('user_module')->addUserLoginLog(
  135.                     $session->get(UserConstants::USER_ID),
  136.                     $request->server->get("REMOTE_ADDR"),
  137.                     $request->request->get('position'),
  138.                     '',
  139.                     '',
  140.                     '',
  141.                     $session->get(UserConstants::USER_LOGIN_ID)
  142.                 );
  143.             } else $loginID $this->get('user_module')->addUserLoginLog(
  144.                 $session->get(UserConstants::USER_ID),
  145.                 $request->server->get("REMOTE_ADDR"),
  146.                 $request->request->get('position'),
  147.                 '',
  148.                 '',
  149.                 '',
  150.                 0
  151.             );
  152.             if ($session->get(UserConstants::ALL_MODULE_ACCESS_FLAG) == 1)
  153.                 $prohibit_list_array = [];
  154.             else if ($curr_position_id != 0)
  155.                 $prohibit_list_array Position::getUserProhibitRouteArray($this->getDoctrine()->getManager(), $curr_position_id$session->get(UserConstants::USER_ID));
  156.             $session->set(UserConstants::USER_LOGIN_ID$loginID);
  157.             $session->set(UserConstants::USER_PROHIBIT_LISTjson_encode($prohibit_list_array));
  158.             $session->set(UserConstants::USER_ROUTE_LISTjson_encode(Position::getUserRouteArray($this->getDoctrine()->getManager(), $request->request->get('position'), $session->get(UserConstants::USER_ID))));
  159.             return $this->redirectToRoute("dashboard");
  160.         }
  161.         $message "";
  162.         $PositionList = array();
  163.         $PL json_decode($session->get(UserConstants::USER_POSITION_LIST), true);
  164.         foreach ($PL as &$positionID) {
  165.             $PositionList[$positionID] = Position::getPositionName($this->getDoctrine()->getManager(), $positionID);
  166.         }
  167.         return $this->render(
  168.             '@Authentication/pages/views/login_position.html.twig',
  169.             array(
  170.                 "message" => $message,
  171.                 'page_title' => 'Users',
  172.                 'position_list' => $PositionList
  173.             )
  174.         );
  175.     }
  176.     //    protected $twig;
  177.     //    protected $debug;
  178.     //
  179.     //    /**
  180.     //     * @param bool $debug Show error (false) or exception (true) pages by default
  181.     //     */
  182.     //    public function __construct(Environment $twig, $debug)
  183.     //    {
  184.     //        $this->twig = $twig;
  185.     //        $this->debug = $debug;
  186.     //    }
  187.     public function TestSmsAction(Request $request)
  188.     {
  189.         $em $this->getDoctrine()->getManager();
  190.         $session $request->getSession();
  191.         $em $this->getDoctrine()->getManager();
  192.         $userAppId $session->get('userAppId');
  193.         $companyId $session->get('userCompanyId');
  194.         if (GeneralConstant::SMS_ENABLED == 1) {
  195.             $company $em->getRepository('ApplicationBundle\\Entity\\Company')->findOneBy(
  196.                 array(
  197.                     'id' => $companyId///material
  198.                 )
  199.             );
  200.             if ($company->getSmsNotificationEnabled() == 1) {
  201.                 $smsData = [];
  202.                 $smsSettings json_decode($company->getSmsSettings(), true);
  203.                 if ($smsSettings != null && !empty($smsSettings)) {
  204.                     $method = isset($smsSettings['method']) ? $smsSettings['method'] : 'GET';
  205.                     $destination_url = isset($smsSettings['destination_url']) ? $smsSettings['destination_url'] : 'http://172.105.70.96:1234';
  206.                     $user_name = isset($smsSettings['user_name']) ? $smsSettings['user_name'] : 'test';
  207.                     $user_name_var = isset($smsSettings['user_name_var']) ? $smsSettings['user_name_var'] : 'Username';
  208.                     $password_var = isset($smsSettings['password_var']) ? $smsSettings['password_var'] : 'Password';
  209.                     $password = isset($smsSettings['password']) ? $smsSettings['password'] : '';
  210.                     $from_number_var = isset($smsSettings['from_number_var']) ? $smsSettings['from_number_var'] : 'From';
  211.                     $from_number = isset($smsSettings['from_number']) ? $smsSettings['from_number'] : '';
  212.                     $to_number_var = isset($smsSettings['to_number_var']) ? $smsSettings['to_number_var'] : 'To';
  213.                     $to_number $request->query->has('To') ? $request->query->get('To') : '01911706483';
  214.                     $text_var = isset($smsSettings['text_var']) ? $smsSettings['text_var'] : 'Message';
  215.                     $text $request->query->has('Message') ? $request->query->get('Message') : 'Test message';
  216.                     return new JsonResponse(System::sendSms(
  217.                         1,
  218.                         $method,
  219.                         $destination_url,
  220.                         $user_name_var,
  221.                         $user_name,
  222.                         $password_var,
  223.                         $password,
  224.                         $from_number_var,
  225.                         $from_number,
  226.                         $to_number_var,
  227.                         $to_number,
  228.                         $text_var,
  229.                         $text,
  230.                         $viewlink ""
  231.                     ));
  232.                 }
  233.             }
  234.             return new JsonResponse(
  235.                 [
  236.                     'companyId' => $companyId,
  237.                     'companyName' => $company->getName(),
  238.                     'enabled' => $company->getSmsNotificationEnabled(),
  239.                     //                    'smsSettings'=>$smsSettings
  240.                 ]
  241.             );
  242.         }
  243.         return new JsonResponse(
  244.             [
  245.                 'success' => false
  246.             ]
  247.         );
  248.     }
  249.     public function SyncCompanyProductToEntityProductAction(Request $request)
  250.     {
  251.         $gocId $request->query->has('gocId') ? $request->query->get('gocId') : 0;
  252.         $companyId $request->query->has('companyId') ? $request->query->get('companyId') : 1;
  253.         $genQueryArray = [];
  254.         $em_goc $this->getDoctrine()->getManager('company_group');
  255.         $em_goc->getConnection()->connect();
  256.         $em $this->getDoctrine()->getManager();
  257.         if ($request->query->has('forceRefresh')) {
  258.             $genQueryArray = [];
  259.             $query "
  260.             TRUNCATE `entity_brand_company`;
  261.             TRUNCATE `entity_item_group`;
  262.             TRUNCATE `entity_products`;
  263.             TRUNCATE `entity_product_categories`;
  264.             TRUNCATE `entity_product_specifications`;
  265.             TRUNCATE `entity_product_sub_categories`;
  266.             TRUNCATE `entity_specification_types`;
  267.             TRUNCATE `entity_unit_type`;
  268.             SELECT * from `entity_unit_type`;";
  269.             $stmt $em_goc->getConnection()->executeStatement($query);
  270.             
  271.             //            $Transactions = $stmt;
  272.             $get_kids_sql 'select * from acc_accounts_head where accounts_head_id not in (select distinct parent_id from acc_accounts_head) ;';
  273.             //UPDATE company SET sales=0, expense=0, payable=0 ,net_worth=0, monthly_growth=0 WHERE 1;';
  274.             $stmt $em->getConnection()->executeStatement($get_kids_sql);
  275.             
  276.             $query $stmt;
  277.         } else
  278.             $genQueryArray = ['globalId' => [0null]];
  279.         //1st step get all company item ids and then check for global id null if its null then the
  280.         // item group is not present in entity so add it
  281.         $company_wise_entities = [
  282.             'Currencies',
  283.             'UnitType',
  284.             'SpecType',
  285.             'BrandCompany',
  286.             'InvItemGroup',
  287.             'InvProductCategories',
  288.             'InvProductSubCategories',
  289.             'InvProductSpecifications',
  290.             'InvSpecificationTypes',
  291.             'InvProducts'
  292.         ];
  293.         $entity_wise_entities = [
  294.             'EntityCurrencies',
  295.             'EntityUnitType',
  296.             'EntitySpecType',
  297.             'EntityBrandCompany',
  298.             'EntityItemGroup',
  299.             'EntityProductCategories',
  300.             'EntityProductSubCategories',
  301.             'EntityProductSpecifications',
  302.             'EntitySpecificationTypes',
  303.             'EntityProducts'
  304.         ];
  305.         ////ITEMGROUPS
  306.         foreach ($company_wise_entities as $k => $cwa) {
  307.             $dataOnCompany $em
  308.                 ->getRepository("ApplicationBundle\\Entity\\" $cwa)
  309.                 ->findBy(
  310.                     $genQueryArray
  311.                 );
  312.             $match_cid_gid_itemgroup = [];  //[cid=>gid]
  313.             $match_cid_gid_itemgroup = [];  //[cid=>gid]
  314.             foreach ($dataOnCompany as $data) {
  315.                 $newClass "\\CompanyGroupBundle\\Entity\\" $entity_wise_entities[$k];
  316.                 $new = new $newClass();
  317.                 //                $new = new \CompanyGroupBundle\Entity\EntityItemGroup();
  318.                 $getters array_filter(get_class_methods($data), function ($method) {
  319.                     return 'get' === substr($method03);
  320.                 });
  321.                 foreach ($getters as $getter) {
  322.                     if ($getter == 'getGlobalId')
  323.                         continue;
  324.                     //                    if ($getter == 'getId')
  325.                     //                        continue;
  326.                     $setMethod str_replace('get''set'$getter);
  327.                     if (method_exists($new$setMethod))
  328.                         $new->{$setMethod}($data->{$getter}()); // `foo!`
  329.                 }
  330.                 $em_goc->persist($new);
  331.                 $em_goc->flush();
  332.                 if ($cwa == 'Currencies') {
  333.                     $data->setGlobalId($new->getCurrencyId());
  334.                     $new->setGlobalId($new->getCurrencyId());
  335.                 } else {
  336.                     $data->setGlobalId($new->getId());
  337.                     $new->setGlobalId($new->getId());
  338.                 }
  339.                 $em->flush();
  340.                 $em_goc->flush();
  341.                 //                $match_cid_gid_itemgroup[$data->getId()] = $new->getId();
  342.             }
  343.         }
  344.         return new JsonResponse(
  345.             array(
  346.                 'data' => $entity_wise_entities
  347.             )
  348.         );
  349.     }
  350.     public function SyncEntityProductToCompanyProductAction(Request $request)
  351.     {
  352.         $gocId $request->query->has('gocId') ? $request->query->get('gocId') : 0;
  353.         $companyId $request->query->has('companyId') ? $request->query->get('companyId') : 1;
  354.         $genQueryArray = [];
  355.         $em_goc $this->getDoctrine()->getManager('company_group');
  356.         $em_goc->getConnection()->connect();
  357.         $em $this->getDoctrine()->getManager();
  358.         if ($request->query->has('forceRefresh')) {
  359.             $genQueryArray = [];
  360.             $query "
  361.             TRUNCATE `brand_company`;
  362.             TRUNCATE `inv_item_group`;
  363.             TRUNCATE `inv_products`;
  364.             TRUNCATE `inv_product_categories`;
  365.             TRUNCATE `inv_product_specifications`;
  366.             TRUNCATE `inv_product_sub_categories`;
  367.             TRUNCATE `inv_specification_types`;
  368.             TRUNCATE `unit_type`;
  369.             SELECT * from `unit_type`;";
  370.             $stmt $em->getConnection()->executeStatement($query);
  371.             
  372.             //            $Transactions = $stmt;
  373.             $get_kids_sql 'select * from acc_accounts_head where accounts_head_id not in (select distinct parent_id from acc_accounts_head) ;';
  374.             //UPDATE company SET sales=0, expense=0, payable=0 ,net_worth=0, monthly_growth=0 WHERE 1;';
  375.             $stmt $em->getConnection()->fetchAllAssociative($get_kids_sql);
  376.             
  377.             $query $stmt;
  378.         } else {
  379.             //            $genQueryArray = ['globalId' => [0, null]];
  380.         }
  381.         //1st step get all company item ids and then check for global id null if its null then the
  382.         // item group is not present in entity so add it
  383.         $company_wise_entities = [
  384.             'Currencies',
  385.             'UnitType',
  386.             'SpecType',
  387.             'BrandCompany',
  388.             'InvItemGroup',
  389.             'InvProductCategories',
  390.             'InvProductSubCategories',
  391.             'InvProductSpecifications',
  392.             'InvSpecificationTypes',
  393.             'InvProducts'
  394.         ];
  395.         $entity_wise_entities = [
  396.             'EntityCurrencies',
  397.             'EntityUnitType',
  398.             'EntitySpecType',
  399.             'EntityBrandCompany',
  400.             'EntityItemGroup',
  401.             'EntityProductCategories',
  402.             'EntityProductSubCategories',
  403.             'EntityProductSpecifications',
  404.             'EntitySpecificationTypes',
  405.             'EntityProducts'
  406.         ];
  407.         foreach ($entity_wise_entities as $k => $ewa) {
  408.             $dataOnEntity $em_goc
  409.                 ->getRepository("CompanyGroupBundle\\Entity\\" $ewa)
  410.                 ->findBy(
  411.                     $genQueryArray
  412.                 );
  413.             $match_cid_gid_itemgroup = [];  //[cid=>gid]
  414.             $match_cid_gid_itemgroup = [];  //[cid=>gid]
  415.             foreach ($dataOnEntity as $data) {
  416.                 $newClass "\\ApplicationBundle\\Entity\\" $company_wise_entities[$k];
  417.                 $rec_exists 0;
  418.                 $new $em
  419.                     ->getRepository("ApplicationBundle\\Entity\\" $company_wise_entities[$k])
  420.                     ->findOneBy(
  421.                         array(
  422.                             'globalId' => $data->getGlobalId()
  423.                         )
  424.                     );
  425.                 if ($new) {
  426.                     $rec_exists 1;
  427.                 } else
  428.                     $new = new $newClass();
  429.                 //                $new = new \CompanyGroupBundle\Entity\EntityItemGroup();
  430.                 $getters array_filter(get_class_methods($data), function ($method) {
  431.                     return 'get' === substr($method03);
  432.                 });
  433.                 foreach ($getters as $getter) {
  434.                     if ($getter == 'getId')
  435.                         continue;
  436.                     $setMethod str_replace('get''set'$getter);
  437.                     if (method_exists($new$setMethod)) {
  438.                         if ($ewa == 'EntityProducts') {
  439.                             if ($rec_exists == 1) {
  440.                                 if (in_array($setMethod, [
  441.                                     'setPurchasePrice',
  442.                                     'setPurchasePriceWoExpense',
  443.                                     'setQty',
  444.                                     'setReorderLevel',
  445.                                     'setBookingQty',
  446.                                     'setNonSalesInvoicedQty',
  447.                                     'setNonSalesReturnReceivedQty',
  448.                                     'setBookingQty',
  449.                                     'setPhysicalQty',
  450.                                 ])) {
  451.                                     continue;
  452.                                 }
  453.                             }
  454.                         }
  455.                         $new->{$setMethod}($data->{$getter}()); // `foo!`
  456.                     }
  457.                 }
  458.                 if ($rec_exists == 0)
  459.                     $em->persist($new);
  460.                 $em->flush();
  461.                 if ($ewa == 'EntityCurrencies') {
  462.                     $new->setGlobalId($data->getCurrencyId());
  463.                 } else {
  464.                     $new->setGlobalId($data->getId());
  465.                 }
  466.                 $em->flush();
  467.                 //                $match_cid_gid_itemgroup[$data->getId()] = $new->getId();
  468.             }
  469.         }
  470.         return new JsonResponse(
  471.             array(
  472.                 'data' => $company_wise_entities
  473.             )
  474.         );
  475.     }
  476.     public function getAppGeneralDashboardDataAction(Request $request)
  477.     {
  478.         $dataFor 'client';
  479.         $personId 0;
  480.         if ($request->query->has('dataFor'))
  481.             $dataFor $request->query->get('dataFor');
  482.         if ($request->request->has('dataFor'))
  483.             $dataFor $request->request->get('dataFor');
  484.         if ($request->query->has('personId'))
  485.             $personId $request->query->get('personId');
  486.         if ($request->request->has('personId'))
  487.             $personId $request->request->get('personId');
  488.         if ($personId == 0)
  489.             return new JsonResponse(
  490.                 array(
  491.                     'success' => false,
  492.                     'data' => [],
  493.                 )
  494.             );
  495.         $session $request->getSession();
  496.         $em $this->getDoctrine()->getManager();
  497.         $userAppId $session->get('userAppId');
  498.         $companyId $session->get('userCompanyId');
  499.         $dataToConnectList = [];
  500.         $appIdList $session->get('appIdList');
  501.         $companyIdListByAppId $session->get('companyIdListByAppId');
  502.         $companyNameListByAppId $session->get('companyNameListByAppId');
  503.         $companyImageListByAppId $session->get('companyImageListByAppId');
  504.         $gocEnabled 0;
  505.         if ($this->container->hasParameter('entity_group_enabled'))
  506.             $gocEnabled $this->container->getParameter('entity_group_enabled');
  507.         $connector $this->container->get('application_connector');
  508.         $connector->resetConnection(
  509.             'default',
  510.             $session->get('gocDbName'),
  511.             $session->get('gocDbUser'),
  512.             $session->get('gocDbPass'),
  513.             $session->get('gocDbHost'),
  514.             $reset true
  515.         );
  516.         $em $this->getDoctrine()->getManager();
  517.         $data = [];
  518.         if ($dataFor == 'client') {
  519.             //get order_count, order_amount,bill_count, bill_amount, collection_amount, due_amount
  520.             $data = [
  521.                 'order_count' => 0,
  522.                 'order_amount' => 0,
  523.                 'invoice_count' => 0,
  524.                 'invoice_amount' => 0,
  525.                 'collection_amount' => 0,
  526.                 'due_amount' => 0,
  527.                 'client_count' => 1,
  528.             ];
  529.             $clientIds = [$personId];
  530.             //order count and amount
  531.             $get_sql "SELECT count(sales_order_id) order_count, sum(so_amount) order_amount
  532. FROM sales_order WHERE approved=1 and sales_order.company_id=" $companyId "  and sales_order.client_id in (" implode(','$clientIds) . ");";
  533.             $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  534.             
  535.             $entries $stmt;
  536.             if (!empty($entries)) {
  537.                 $data['order_count'] = $entries[0]['order_count'];
  538.                 $data['order_amount'] = $entries[0]['order_amount'];
  539.             }
  540.             //invoice
  541.             $get_sql "SELECT count(sales_invoice_id) invoice_count, sum(invoice_amount) invoice_amount
  542. FROM sales_invoice WHERE approved=1 and sales_invoice.company_id=" $companyId "  and sales_invoice.client_id in (" implode(','$clientIds) . ");";
  543.             $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  544.             
  545.             $entries $stmt;
  546.             if (!empty($entries)) {
  547.                 $data['invoice_count'] = $entries[0]['invoice_count'];
  548.                 $data['invoice_amount'] = $entries[0]['invoice_amount'];
  549.             }
  550.             //now collection
  551.             $allocationSourceSql $this->buildAllocationAwareTransactionSourceSql(array(
  552.                 'document_type' => 6,
  553.                 'company_id' => $companyId,
  554.                 'start_date' => null,
  555.                 'end_date' => null,
  556.                 'approved' => 1,
  557.                 'ledger_hit' => 1,
  558.             ));
  559.             $get_sql "SELECT SUM(CASE WHEN alloc_rows.position = 'cr' THEN alloc_rows.allocation_amount ELSE 0 END) positive_amount,
  560. SUM(CASE WHEN alloc_rows.position = 'dr' THEN alloc_rows.allocation_amount ELSE 0 END) negative_amount,client_type.client_type_id, client_type.name, acc_clients.client_id, acc_clients.type, acc_clients.client_due, acc_clients.client_id
  561.  FROM " $allocationSourceSql " alloc_rows
  562.    join acc_clients on acc_clients.accounts_head_id=alloc_rows.accounts_head_id or acc_clients.advance_head_id=alloc_rows.accounts_head_id
  563.   join client_type on acc_clients.type=client_type.client_type_id
  564.   WHERE acc_clients.company_id=" $companyId " and acc_clients.client_id in (" implode(','$clientIds) . ") ";
  565.             $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  566.             
  567.             $entries $stmt;
  568.             $clientTypes = [];
  569.             $clientTypeNames = [];
  570.             $alreadyCids = [];
  571.             foreach ($entries as $entry) {
  572.                 $data['collection_amount'] += (* ($entry['positive_amount'] - $entry['negative_amount']));
  573.                 if (!in_array($entry['client_id'], $alreadyCids)) {
  574.                     $data['due_amount'] += ($entry['client_due']);
  575.                     $alreadyCids[] = $entry['client_id'];
  576.                 }
  577.             }
  578.         }
  579.         if ($dataFor == 'sales_user') {
  580.             //get order_count, order_amount,bill_count, bill_amount, collection_amount, due_amount
  581.             $data = [
  582.                 'order_count' => 0,
  583.                 'order_amount' => 0,
  584.                 'invoice_count' => 0,
  585.                 'invoice_amount' => 0,
  586.                 'collection_amount' => 0,
  587.                 'due_amount' => 0,
  588.                 'client_count' => 0,
  589.             ];
  590.             $clientIds = [];
  591.             $salesPersonIds = [];
  592.             $allSalespersonFlag 1//temp
  593.             if ($allSalespersonFlag != 1) {
  594.                 $query $em->getRepository('ApplicationBundle\\Entity\\Employee')->findOneBy(
  595.                     array(
  596.                         'userId' => $personId
  597.                     )
  598.                 );
  599.                 if ($query)
  600.                     $salesPersonIds[] = $query->getEmployeeId();
  601.             }
  602.             //Client count
  603.             $get_sql "SELECT  client_id
  604. FROM acc_clients WHERE  acc_clients.company_id=" $companyId " ";
  605.             if ($allSalespersonFlag != 1)
  606.                 $get_sql .= " and acc_clients.sales_person_id in (" implode(','$salesPersonIds) . ");";
  607.             else
  608.                 $get_sql .= " ;";
  609.             $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  610.             
  611.             $entries $stmt;
  612.             if (!empty($entries)) {
  613.                 foreach ($entries as $entry) {
  614.                     $data['client_count'] += 1;
  615.                     $clientIds[] = $entry['client_id'];
  616.                 }
  617.             }
  618.             //order count and amount
  619.             if (!empty($clientIds)) {
  620.                 $get_sql "SELECT count(sales_order_id) order_count, sum(so_amount) order_amount
  621. FROM sales_order WHERE approved=1 and sales_order.company_id=" $companyId "  and sales_order.client_id in (" implode(','$clientIds) . ");";
  622.                 $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  623.                 
  624.                 $entries $stmt;
  625.                 if (!empty($entries)) {
  626.                     $data['order_count'] = $entries[0]['order_count'];
  627.                     $data['order_amount'] = $entries[0]['order_amount'];
  628.                 }
  629.                 //invoice
  630.                 $get_sql "SELECT count(sales_invoice_id) invoice_count, sum(invoice_amount) invoice_amount
  631. FROM sales_invoice WHERE approved=1 and sales_invoice.company_id=" $companyId "  and sales_invoice.client_id in (" implode(','$clientIds) . ");";
  632.                 $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  633.                 
  634.                 $entries $stmt;
  635.                 if (!empty($entries)) {
  636.                     $data['invoice_count'] = $entries[0]['invoice_count'];
  637.                     $data['invoice_amount'] = $entries[0]['invoice_amount'];
  638.                 }
  639.                 //now collection
  640.                 $allocationSourceSql $this->buildAllocationAwareTransactionSourceSql(array(
  641.                     'document_type' => 6,
  642.                     'approved' => 1,
  643.                     'ledger_hit' => 1,
  644.                 ));
  645.                 $get_sql "SELECT SUM(CASE WHEN alloc_rows.position = 'cr' THEN alloc_rows.allocation_amount ELSE 0 END) positive_amount,
  646. SUM(CASE WHEN alloc_rows.position = 'dr' THEN alloc_rows.allocation_amount ELSE 0 END) negative_amount,client_type.client_type_id, client_type.name, acc_clients.client_id, acc_clients.type, acc_clients.client_due, acc_clients.client_id
  647.  FROM " $allocationSourceSql " alloc_rows
  648.    join acc_clients on acc_clients.accounts_head_id=alloc_rows.accounts_head_id or acc_clients.advance_head_id=alloc_rows.accounts_head_id
  649.   join client_type on acc_clients.type=client_type.client_type_id
  650.   WHERE acc_clients.company_id=" $companyId " and acc_clients.client_id in (" implode(','$clientIds) . ") ";
  651.                 $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  652.                 
  653.                 $entries $stmt;
  654.                 $clientTypes = [];
  655.                 $clientTypeNames = [];
  656.                 $alreadyCids = [];
  657.                 foreach ($entries as $entry) {
  658.                     $data['collection_amount'] += (* ($entry['positive_amount'] - $entry['negative_amount']));
  659.                     if (!in_array($entry['client_id'], $alreadyCids)) {
  660.                         $data['due_amount'] += ($entry['client_due']);
  661.                         $alreadyCids[] = $entry['client_id'];
  662.                     }
  663.                 }
  664.             }
  665.         }
  666.         if ($dataFor == 'user') {
  667.             //get order_count, payment_amount,
  668.         }
  669.         return new JsonResponse(
  670.             array(
  671.                 'success' => true,
  672.                 'data' => $data,
  673.                 'dataFor' => $dataFor,
  674.                 'personId' => $personId,
  675.             )
  676.         );
  677.     }
  678.     public function getManagementDashboardDataAction(Request $request)
  679.     {
  680.         $session $request->getSession();
  681.         $data = array(
  682.             'cash_and_bank_position' => [],
  683.             'order_and_client_count' => [],
  684.             'expense_vs_revenue' => [],
  685.             'receivable_position' => [],
  686.             'payable_position' => [],
  687.             'expense_position' => [],
  688.             'inventory_position' => [],
  689.             'production_position' => [],
  690.             'sales_position' => [],
  691.             'collection_position' => [],
  692.             'market_return_position' => [],
  693.             'top_selling_item_position' => [],
  694.             'top_selling_client_position' => [],
  695.         );
  696.         $em $this->getDoctrine()->getManager();
  697.         $reportsToGet = [
  698.             'cash_and_bank_position',
  699.             'order_and_client_count',
  700.             'expense_vs_revenue',
  701.             'receivable_position',
  702.             'payable_position',
  703.             'expense_position',
  704.             'inventory_position',
  705.             'production_position',
  706.             'sales_position',
  707.             'collection_position',
  708.             'market_return_position',
  709.             'top_selling_item_position',
  710.             'top_selling_client_position',
  711.         ];
  712.         //        $periodType='day'; //day,month,week,year,quarter etc
  713.         $periodType 'month'//day,month,week,year,quarter etc
  714.         if ($request->request->has('reportsToGet')) {
  715.             if ($request->request->get('reportsToGet') != 'all' && !in_array('all'$request->request->get('reportsToGet'))) {
  716.                 $reportsToGet $request->request->get('reportsToGet');
  717.             }
  718.         }
  719.         if ($request->request->has('periodType')) {
  720.             $periodType $request->request->get('periodType');
  721.         }
  722.         $userAppId $session->get('userAppId');
  723.         $dataToConnectList = [];
  724.         $appIdList $session->get('appIdList');
  725.         $companyIdListByAppId $session->get('companyIdListByAppId');
  726.         $companyNameListByAppId $session->get('companyNameListByAppId');
  727.         $companyImageListByAppId $session->get('companyImageListByAppId');
  728.         $gocEnabled 0;
  729.         if ($this->container->hasParameter('entity_group_enabled'))
  730.             $gocEnabled $this->container->getParameter('entity_group_enabled');
  731.         $thisPeriodStartDate '';
  732.         $lastPeriodStartDate '';
  733.         $thisPeriodEndDate '';
  734.         $lastPeriodEndDate '';
  735.         $today = new \DateTime();
  736.         if ($periodType == 'month') {
  737.             $thisPeriodEndDate $today->format('Y-m-d');
  738.             $thisPeriodStartDate $today->format('Y-m-') . '01';
  739.             $currDate = new \DateTime($thisPeriodStartDate);
  740.             $currDate->modify('-1 day');
  741.             $lastPeriodEndDate $currDate->format('Y-m-d');
  742.             $lastPeriodStartDate $currDate->format('Y-m-') . '01';
  743.         } else if ($periodType == 'week') {
  744.             $thisPeriodEndDate $today->format('Y-m-d');
  745.             $thisWeekStartDate date("Y-m-d"strtotime("previous saturday"));
  746.             $thisPeriodStartDate date("Y-m-d"strtotime("previous saturday"));
  747.             $currDate = new \DateTime($thisPeriodStartDate);
  748.             $currDate->modify('-1 day');
  749.             $lastPeriodEndDate $currDate->format('Y-m-d');
  750.             $currDate->modify('-6 day');
  751.             $lastPeriodStartDate $currDate->format('Y-m-d');
  752.         } else if ($periodType == 'quarter') {
  753.             $thisPeriodEndDate $today->format('Y-m-d');
  754.             $thisWeekStartDate date("Y-m-d"strtotime("previous saturday"));
  755.             $thisPeriodStartDate date("Y-m-d"strtotime("previous saturday"));
  756.             $currDate = new \DateTime($thisPeriodStartDate);
  757.             $currDate->modify('-1 day');
  758.             $lastPeriodEndDate $currDate->format('Y-m-d');
  759.             $currDate->modify('-6 day');
  760.             $lastPeriodStartDate $currDate->format('Y-m-d');
  761.         } else if ($periodType == 'year') {
  762.             $thisPeriodEndDate $today->format('Y-m-d');
  763.             //            $thisWeekStartDate = date("Y-m-d", strtotime("previous saturday"));
  764.             $thisPeriodStartDate = ($today->format('Y')) . '-01-01';
  765.             $currDate = new \DateTime($thisPeriodStartDate);
  766.             $currDate->modify('-1 day');
  767.             $lastPeriodEndDate $currDate->format('Y-m-d');
  768.             $lastPeriodStartDate = ($currDate->format('Y')) . '-01-01';;
  769.         }
  770.         $companyListData = [];
  771.         foreach ($appIdList as $appId) {
  772.             //queryonly if mor ethan one app id
  773.             $skip 0;
  774.             if ($appId == $userAppId) {
  775.                 $connector $this->container->get('application_connector');
  776.                 $connector->resetConnection(
  777.                     'default',
  778.                     $session->get('gocDbName'),
  779.                     $session->get('gocDbUser'),
  780.                     $session->get('gocDbPass'),
  781.                     $session->get('gocDbHost'),
  782.                     $reset true
  783.                 );
  784.                 $em $this->getDoctrine()->getManager();
  785.             } else {
  786.                 $dataToConnect System::changeDoctrineManagerByAppId($this->getDoctrine()->getManager('company_group'), $gocEnabled$appId);
  787.                 $dataToConnectList[] = $dataToConnect;
  788.                 if (!empty($dataToConnect)) {
  789.                     $connector $this->container->get('application_connector');
  790.                     $connector->resetConnection(
  791.                         'default',
  792.                         $dataToConnect['dbName'],
  793.                         $dataToConnect['dbUser'],
  794.                         $dataToConnect['dbPass'],
  795.                         $dataToConnect['dbHost'],
  796.                         $reset true
  797.                     );
  798.                     $em $this->getDoctrine()->getManager();
  799.                 } else {
  800.                     $skip 1;
  801.                 }
  802.             }
  803.             if ($skip == 1)
  804.                 continue;
  805.             //                $companyListData[] = Company::getCompanyListWithImage($em);
  806.             //                $get_sql = "SELECT * FROM company ";
  807.             //                $stmt = $em->getConnection()->executeStatement($get_sql);
  808.             //                
  809.             //                $entries = $stmt;
  810.             //                $companyListData[] = $entries;
  811.             //                foreach ($companyIdListByAppId as $app_company_index)
  812.             if (isset($companyIdListByAppId[$appId])) {
  813.                 foreach ($companyIdListByAppId[$appId] as $app_company_index) {
  814.                     //exp vs rev
  815.                     if (in_array('expense_vs_revenue'$reportsToGet)) {
  816.                         $acHeadList = [];
  817.                         $companyId explode('_'$app_company_index)[1];
  818.                         $acHeadDataById = [];
  819.                         $thisBalanceDataByAcHead = [];
  820.                         $lastBalanceDataByAcHead = [];
  821.                         $mon_names = ["""January""February""March""April""May""June""July""August""September""October""November""December"];
  822.                         $limit 12;
  823.                         $get_kids_sql "SELECT expense, revenue, `date` summ_date
  824.                           FROM monthly_summary
  825.                             where monthly_summary.company_id=$companyId
  826.                             AND ( monthly_summary.branch_id=0 or monthly_summary.branch_id is null) ";
  827.                         //                               GROUP BY monthly_summary.`date`
  828.                         $get_kids_sql .= " ORDER BY monthly_summary.`date` DESC  limit " $limit;
  829.                         $stmt $em->getConnection()->fetchAllAssociative($get_kids_sql);
  830.                         
  831.                         $pl $stmt;
  832.                         $curr_date = new \DateTime();
  833.                         $curr_mon = ($curr_date->format('m'));
  834.                         $curr_year = ($curr_date->format('Y'));
  835.                         $object_list = [];
  836.                         $debug_list = [];
  837.                         $list = [];
  838.                         $timeStampList = [];
  839.                         //        $first
  840.                         foreach ($pl as $key => $entry) {
  841.                             $qryDate = new \DateTime($entry['summ_date']);
  842.                             $qrMon $qryDate->format('m');;
  843.                             $qrYr $qryDate->format('Y');;
  844.                             $object_list[$qrYr '_' $qrMon] = $entry;
  845.                         }
  846.                         for ($k 0$k 11$k++) {
  847.                             $debug_list[$k] = $curr_year '_' $curr_mon;
  848.                             $currTimeStamp strtotime($curr_year "-" $curr_mon '-1');
  849.                             $currTimeStampMili $currTimeStamp 1000;
  850.                             $cashAddition 0;
  851.                             $bankAddition 0;
  852.                             if (isset($object_list[$curr_year '_' $curr_mon])) {
  853.                                 $entry $object_list[$curr_year '_' $curr_mon];
  854.                                 $list['monthList'][] = $mon_names[$curr_mon];
  855.                                 $list['revenue'][] = round($entry['revenue']);
  856.                                 $list['tsCommaRevenue'][] = [$currTimeStampMiliround($entry['revenue'])];
  857.                                 $list['expense'][] = round($entry['expense']);
  858.                                 $list['tsCommaExpense'][] = [$currTimeStampMiliround($entry['expense'])];
  859.                             } else {
  860.                                 $list['monthList'][] = $mon_names[($curr_mon)];
  861.                                 $list['revenue'][] = 0;
  862.                                 $list['expense'][] = 0;
  863.                                 $list['tsCommaRevenue'][] = [$currTimeStampMili0];
  864.                                 $list['tsCommaExpense'][] = [$currTimeStampMili0];
  865.                             }
  866.                             $curr_mon--;
  867.                             if ($curr_mon <= 0) {
  868.                                 $curr_mon 12;
  869.                                 $curr_year--;
  870.                             }
  871.                             //new end
  872.                         }
  873.                         $data['expense_vs_revenue'][$app_company_index] = $list;
  874.                     }
  875.                     //cash and bank position
  876.                     if (in_array('cash_and_bank_position'$reportsToGet)) {
  877.                         $acHeadList = [];
  878.                         $companyId explode('_'$app_company_index)[1];
  879.                         $acHeadDataById = [];
  880.                         $thisBalanceDataByAcHead = [];
  881.                         $lastBalanceDataByAcHead = [];
  882.                         $bank_settings $em->getRepository('ApplicationBundle\\Entity\\AccSettings')->findOneBy(array(
  883.                             'name' => 'bank_parents',
  884.                             //                        'CompanyId'=>$companyId
  885.                         ));
  886.                         $bank_id_list = [];
  887.                         if ($bank_settings)
  888.                             $bank_id_list json_decode($bank_settings->getData());
  889.                         $bank_child_id_list = [];
  890.                         $likeQuery '';
  891.                         foreach ($bank_id_list as $p) {
  892.                             $likeQuery .= "OR path_tree like '%/" $p "%/' ";
  893.                         }
  894.                         $get_sql "SELECT * FROM acc_accounts_head WHERE acc_accounts_head.company_id=" $companyId " AND  accounts_head_id not in (select distinct parent_id from acc_accounts_head)and (1=0 " $likeQuery ") ";
  895.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  896.                         
  897.                         $entries $stmt;
  898.                         foreach ($entries as $entry) {
  899.                             $has_payments 1;
  900.                             $bank_child_id_list[] = $entry['accounts_head_id'];
  901.                             $acHeadList[] = $entry['accounts_head_id'];
  902.                             $acHeadDataById[$entry['accounts_head_id']]['name'] = $entry['name'];
  903.                         }
  904.                         $cash_settings $em->getRepository('ApplicationBundle\\Entity\\AccSettings')->findOneBy(array(
  905.                             'name' => 'cash_parents'
  906.                             //                        'CompanyId'=>$companyId
  907.                         ));
  908.                         $cash_id_list = [];
  909.                         if ($cash_settings)
  910.                             $cash_id_list json_decode($cash_settings->getData());
  911.                         $cash_child_id_list = [];
  912.                         $likeQuery '';
  913.                         foreach ($cash_id_list as $p) {
  914.                             $likeQuery .= "OR path_tree like '%/" $p "%/' ";
  915.                         }
  916.                         $get_sql "SELECT * FROM acc_accounts_head WHERE acc_accounts_head.company_id=" $companyId " AND accounts_head_id not in (select distinct parent_id from acc_accounts_head)and (1=0 " $likeQuery ") ";
  917.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  918.                         
  919.                         $entries $stmt;
  920.                         foreach ($entries as $entry) {
  921.                             $has_payments 1;
  922.                             $cash_child_id_list[] = $entry['accounts_head_id'];
  923.                             $acHeadList[] = $entry['accounts_head_id'];
  924.                             $acHeadDataById[$entry['accounts_head_id']]['name'] = $entry['name'];
  925.                         }
  926.                         $thisBalance_data Accounts::GetBalanceOnDate($em$thisPeriodEndDate, []);
  927.                         $lastBalance_data Accounts::GetBalanceOnDate($em$lastPeriodEndDate, []);
  928.                         foreach ($acHeadList as $acHead) {
  929.                             $thisBalanceDataByAcHead[$acHead]['balance'] = $thisBalance_data[$acHead]['end_balance']['balance'];
  930.                             $lastBalanceDataByAcHead[$acHead]['balance'] = $lastBalance_data[$acHead]['end_balance']['balance'];
  931.                         }
  932.                         $thisReportData = array(
  933.                             'accountsHeadList' => $acHeadList,
  934.                             'acHeadDataById' => $acHeadDataById,
  935.                             'cash_child_id_list' => $cash_child_id_list,
  936.                             'bank_child_id_list' => $bank_child_id_list,
  937.                             'thisBalanceDataByAcHead' => $thisBalanceDataByAcHead,
  938.                             'lastBalanceDataByAcHead' => $lastBalanceDataByAcHead,
  939.                         );
  940.                         $data['cash_and_bank_position'][$app_company_index] = $thisReportData;
  941.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  942.                     }
  943.                     //Expense Position
  944.                     if (in_array('expense_position'$reportsToGet)) {
  945.                         $acHeadList = [];
  946.                         $companyId explode('_'$app_company_index)[1];
  947.                         $acHeadDataById = [];
  948.                         $thisBalanceDataByAcHead = [];
  949.                         $lastBalanceDataByAcHead = [];
  950.                         $get_sql "SELECT * FROM acc_accounts_head WHERE acc_accounts_head.company_id=" $companyId "
  951.                         AND acc_accounts_head.head_level= 2 ";
  952.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  953.                         
  954.                         $entries $stmt;
  955.                         foreach ($entries as $entry) {
  956.                             $has_payments 1;
  957.                             $cash_child_id_list[] = $entry['accounts_head_id'];
  958.                             $acHeadList[] = $entry['accounts_head_id'];
  959.                             $acHeadDataById[$entry['accounts_head_id']]['name'] = $entry['name'];
  960.                         }
  961.                         $thisBalance_data Accounts::GetPeriodicDataByType($em$type 'exp'$level_to_group_by 1$parent_id_list = [], $expand_level 1$thisPeriodStartDate$thisPeriodEndDate'_during_', [], [], [], false);
  962.                         $lastBalance_data Accounts::GetPeriodicDataByType($em$type 'exp'$level_to_group_by 1$parent_id_list = [], $expand_level 1$lastPeriodStartDate$lastPeriodEndDate'_during_', [], [], [], false);
  963.                         $skipHeadIds = [];
  964.                         foreach ($thisBalance_data as $parentHead => $balanceData) {
  965.                             foreach ($balanceData['data'] as $acHead => $headData) {
  966.                                 if (!in_array($acHead$acHeadList))
  967.                                     continue;
  968.                                 $thisBalanceDataByAcHead[$acHead]['balance'] = $headData['head_balance'];
  969.                                 if (isset($lastBalance_data[$parentHead])) {
  970.                                     if (isset($lastBalance_data[$parentHead]['data'][$acHead]))
  971.                                         $lastBalanceDataByAcHead[$acHead]['balance'] = $lastBalance_data[$parentHead]['data'][$acHead]['head_balance'];
  972.                                     else
  973.                                         $lastBalanceDataByAcHead[$acHead]['balance'] = 0;
  974.                                 } else
  975.                                     $lastBalanceDataByAcHead[$acHead]['balance'] = 0;
  976.                                 $skipHeadIds[] = $acHead;
  977.                             }
  978.                         }
  979.                         foreach ($lastBalance_data as $parentHead => $balanceData) {
  980.                             foreach ($balanceData['data'] as $acHead => $headData) {
  981.                                 if (in_array($acHead$skipHeadIds))
  982.                                     continue;
  983.                                 if (!in_array($acHead$acHeadList))
  984.                                     continue;
  985.                                 $lastBalanceDataByAcHead[$acHead]['balance'] = $headData['head_balance'];
  986.                                 if (isset($thisBalance_data[$parentHead])) {
  987.                                     if (isset($thisBalance_data[$parentHead]['data'][$acHead]))
  988.                                         $thisBalanceDataByAcHead[$acHead]['balance'] = $thisBalance_data[$parentHead]['data'][$acHead]['head_balance'];
  989.                                     else
  990.                                         $thisBalanceDataByAcHead[$acHead]['balance'] = 0;
  991.                                 } else
  992.                                     $thisBalanceDataByAcHead[$acHead]['balance'] = 0;
  993.                                 $skipHeadIds[] = $acHead;
  994.                             }
  995.                         }
  996.                         $thisReportData = array(
  997.                             'accountsHeadList' => $acHeadList,
  998.                             //                            'thisBalance_data' => $thisBalance_data,
  999.                             'confirmedHeadList' => $skipHeadIds,
  1000.                             'acHeadDataById' => $acHeadDataById,
  1001.                             'thisBalanceDataByAcHead' => $thisBalanceDataByAcHead,
  1002.                             'lastBalanceDataByAcHead' => $lastBalanceDataByAcHead,
  1003.                         );
  1004.                         $data['expense_position'][$app_company_index] = $thisReportData;
  1005.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  1006.                     }
  1007.                     //Payable Position
  1008.                     if (in_array('payable_position'$reportsToGet)) {
  1009.                         $acHeadList = [];
  1010.                         $companyId explode('_'$app_company_index)[1];
  1011.                         $acHeadDataById = [];
  1012.                         $thisBalanceDataByAcHead = [];
  1013.                         $lastBalanceDataByAcHead = [];
  1014.                         $filter_settings $em->getRepository('ApplicationBundle\\Entity\\AccSettings')->findOneBy(array(
  1015.                             'name' => 'payable_parents',
  1016.                             //                        'CompanyId'=>$companyId
  1017.                         ));
  1018.                         $filter_head_parents_id_list = [];
  1019.                         if ($filter_settings)
  1020.                             $filter_head_parents_id_list json_decode($filter_settings->getData());
  1021.                         $likeQuery '';
  1022.                         foreach ($filter_head_parents_id_list as $p) {
  1023.                             $likeQuery .= "OR path_tree like '%/" $p "%/' ";
  1024.                         }
  1025.                         $get_sql "SELECT * FROM acc_accounts_head WHERE acc_accounts_head.company_id=" $companyId "
  1026.                          and (1=0 " $likeQuery ") ";
  1027.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1028.                         
  1029.                         $entries $stmt;
  1030.                         foreach ($entries as $entry) {
  1031.                             $has_payments 1;
  1032.                             $acHeadList[] = $entry['accounts_head_id'];
  1033.                             $acHeadDataById[$entry['accounts_head_id']]['name'] = $entry['name'];
  1034.                         }
  1035.                         //                        $get_sql = "SELECT * FROM acc_accounts_head WHERE acc_accounts_head.company_id=" . $companyId . "
  1036.                         //                        AND acc_accounts_head.head_level= 2 and acc_accounts_head.type='lib'";
  1037.                         //
  1038.                         //                        $stmt = $em->getConnection()->executeStatement($get_sql);
  1039.                         //                        
  1040.                         //                        $entries = $stmt;
  1041.                         //
  1042.                         //                        foreach ($entries as $entry) {
  1043.                         //                            $has_payments = 1;
  1044.                         //                            $cash_child_id_list[] = $entry['accounts_head_id'];
  1045.                         //                            $acHeadList[] = $entry['accounts_head_id'];
  1046.                         //                            $acHeadDataById[$entry['accounts_head_id']]['name'] = $entry['name'];
  1047.                         //                        }
  1048.                         $thisBalance_data Accounts::GetPeriodicDataByType($em$type 'lib'$level_to_group_by 2$parent_id_list = [], $expand_level 1$thisPeriodStartDate$thisPeriodEndDate'_during_', [], [], [], false);
  1049.                         $lastBalance_data Accounts::GetPeriodicDataByType($em$type 'lib'$level_to_group_by 2$parent_id_list = [], $expand_level 1$lastPeriodStartDate$lastPeriodEndDate'_during_', [], [], [], false);
  1050.                         $skipHeadIds = [];
  1051.                         foreach ($thisBalance_data as $parentHead => $balanceData) {
  1052.                             foreach ($balanceData['data'] as $acHead => $headData) {
  1053.                                 if (!(in_array($acHead$acHeadList)))
  1054.                                     continue;
  1055.                                 if ($headData['head_level'] > 4)
  1056.                                     continue;
  1057.                                 //                                $thisBalanceDataByAcHead[$acHead]['balance'] = $headData['head_balance'];
  1058.                                 $thisBalanceDataByAcHead[$acHead]['balance'] = $headData['end_balance']['balance'];
  1059.                                 if (isset($lastBalance_data[$parentHead])) {
  1060.                                     if (isset($lastBalance_data[$parentHead]['data'][$acHead]))
  1061.                                         //                                        $lastBalanceDataByAcHead[$acHead]['balance'] = $lastBalance_data[$parentHead]['data'][$acHead]['head_balance'];
  1062.                                         $lastBalanceDataByAcHead[$acHead]['balance'] = $lastBalance_data[$parentHead]['data'][$acHead]['end_balance']['balance'];
  1063.                                     else
  1064.                                         $lastBalanceDataByAcHead[$acHead]['balance'] = 0;
  1065.                                 } else
  1066.                                     $lastBalanceDataByAcHead[$acHead]['balance'] = 0;
  1067.                                 $skipHeadIds[] = $acHead;
  1068.                             }
  1069.                         }
  1070.                         foreach ($lastBalance_data as $parentHead => $balanceData) {
  1071.                             foreach ($balanceData['data'] as $acHead => $headData) {
  1072.                                 if (in_array($acHead$skipHeadIds))
  1073.                                     continue;
  1074.                                 if (!in_array($acHead$acHeadList))
  1075.                                     continue;
  1076.                                 if ($headData['head_level'] > 4)
  1077.                                     continue;
  1078.                                 $lastBalanceDataByAcHead[$acHead]['balance'] = $headData['end_balance']['balance'];
  1079.                                 if (isset($thisBalance_data[$parentHead])) {
  1080.                                     if (isset($thisBalance_data[$parentHead]['data'][$acHead]))
  1081.                                         $thisBalanceDataByAcHead[$acHead]['balance'] = $thisBalance_data[$parentHead]['data'][$acHead]['end_balance']['balance'];
  1082.                                     else
  1083.                                         $thisBalanceDataByAcHead[$acHead]['balance'] = 0;
  1084.                                 } else
  1085.                                     $thisBalanceDataByAcHead[$acHead]['balance'] = 0;
  1086.                                 $skipHeadIds[] = $acHead;
  1087.                             }
  1088.                         }
  1089.                         $thisReportData = array(
  1090.                             'accountsHeadList' => $acHeadList,
  1091.                             //                            'thisBalance_data' => $thisBalance_data,
  1092.                             'confirmedHeadList' => $skipHeadIds,
  1093.                             'acHeadDataById' => $acHeadDataById,
  1094.                             'thisBalanceDataByAcHead' => $thisBalanceDataByAcHead,
  1095.                             'lastBalanceDataByAcHead' => $lastBalanceDataByAcHead,
  1096.                         );
  1097.                         $data['payable_position'][$app_company_index] = $thisReportData;
  1098.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  1099.                     }
  1100.                     //Receivable Position
  1101.                     if (in_array('receivable_position'$reportsToGet)) {
  1102.                         $acHeadList = [];
  1103.                         $companyId explode('_'$app_company_index)[1];
  1104.                         $acHeadDataById = [];
  1105.                         $thisBalanceDataByAcHead = [];
  1106.                         $lastBalanceDataByAcHead = [];
  1107.                         //                        $filter_settings = $em->getRepository('ApplicationBundle\\Entity\\AccSettings')->findOneBy(array(
  1108.                         //                            'name' => 'receivable_parents',
  1109.                         ////                        'CompanyId'=>$companyId
  1110.                         //                        ));
  1111.                         //                        $filter_head_parents_id_list = [];
  1112.                         //                        if ($filter_settings)
  1113.                         //                            $filter_head_parents_id_list = json_decode($filter_settings->getData());
  1114.                         //                        $likeQuery = '';
  1115.                         //                        foreach ($filter_head_parents_id_list as $p) {
  1116.                         //                            $likeQuery .= "OR path_tree like '%/" . $p . "%/' ";
  1117.                         //                        }
  1118.                         //                        $get_sql = "SELECT * FROM acc_accounts_head WHERE acc_accounts_head.company_id=" . $companyId . "
  1119.                         //                         and (1=0 " . $likeQuery . ") ";
  1120.                         $get_sql "SELECT acc_accounts_head.*  FROM acc_accounts_head
  1121.  WHERE acc_accounts_head.company_id=" $companyId "
  1122.                          and  ( acc_accounts_head.accounts_head_id in (select distinct accounts_head_id from acc_clients)
  1123.                           OR acc_accounts_head.accounts_head_id in (select distinct advance_head_id from acc_clients)
  1124.                          ) ";
  1125.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1126.                         
  1127.                         $entries $stmt;
  1128.                         $account_head_ids_by_client_type = [];
  1129.                         foreach ($entries as $entry) {
  1130.                             $has_payments 1;
  1131.                             $acHeadList[] = $entry['accounts_head_id'];
  1132.                             $acHeadDataById[$entry['accounts_head_id']]['name'] = $entry['name'];
  1133.                         }
  1134.                         $get_sql "SELECT acc_clients.*  FROM acc_clients
  1135.  WHERE acc_clients.company_id=" $companyId;
  1136.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1137.                         
  1138.                         $entries $stmt;
  1139.                         $clientTypeListArray Client::ClientTypeList($em, [$companyId], true);
  1140.                         $clientTypesOfHeads = [];
  1141.                         foreach ($entries as $entry) {
  1142.                             if (!isset($account_head_ids_by_client_type[$entry['type']]))
  1143.                                 $account_head_ids_by_client_type[$entry['type']] = [];
  1144.                             $account_head_ids_by_client_type[$entry['type']][] = $entry['accounts_head_id'];
  1145.                             $clientTypesOfHeads[$entry['accounts_head_id']] = $entry['type'];
  1146.                             if ($entry['accounts_head_id'] != $entry['advance_head_id']) {
  1147.                                 $account_head_ids_by_client_type[$entry['type']][] = $entry['advance_head_id'];
  1148.                                 $clientTypesOfHeads[$entry['advance_head_id']] = $entry['type'];
  1149.                             }
  1150.                         }
  1151.                         //                        $get_sql = "SELECT * FROM acc_accounts_head WHERE acc_accounts_head.company_id=" . $companyId . "
  1152.                         //                        AND acc_accounts_head.head_level= 2 and acc_accounts_head.type='lib'";
  1153.                         //
  1154.                         //                        $stmt = $em->getConnection()->executeStatement($get_sql);
  1155.                         //                        
  1156.                         //                        $entries = $stmt;
  1157.                         //
  1158.                         //                        foreach ($entries as $entry) {
  1159.                         //                            $has_payments = 1;
  1160.                         //                            $cash_child_id_list[] = $entry['accounts_head_id'];
  1161.                         //                            $acHeadList[] = $entry['accounts_head_id'];
  1162.                         //                            $acHeadDataById[$entry['accounts_head_id']]['name'] = $entry['name'];
  1163.                         //                        }
  1164.                         $thisBalance_data Accounts::GetPeriodicDataByType($em$type 'ast'$level_to_group_by 2$parent_id_list = [], $expand_level 1$thisPeriodStartDate$thisPeriodEndDate'_during_', [], [], [], true);
  1165.                         $lastBalance_data Accounts::GetPeriodicDataByType($em$type 'ast'$level_to_group_by 2$parent_id_list = [], $expand_level 1$lastPeriodStartDate$lastPeriodEndDate'_during_', [], [], [], true);
  1166.                         $skipHeadIds = [];
  1167.                         $thisBalanceDataByClientType = [];
  1168.                         $lastBalanceDataByClientType = [];
  1169.                         foreach ($clientTypeListArray as $ct) {
  1170.                             $thisBalanceDataByClientType[$ct['id']] = 0;
  1171.                             $lastBalanceDataByClientType[$ct['id']] = 0;
  1172.                         }
  1173.                         foreach ($thisBalance_data as $parentHead => $balanceData) {
  1174.                             foreach ($balanceData['data'] as $acHead => $headData) {
  1175.                                 if (!(in_array($acHead$acHeadList)))
  1176.                                     continue;
  1177.                                 //                                if ($headData['head_level'] > 4)
  1178.                                 //                                    continue;
  1179.                                 $thisBalanceDataByAcHead[$acHead]['balance'] = $headData['end_balance']['balance'];
  1180.                                 if (isset($lastBalance_data[$parentHead])) {
  1181.                                     if (isset($lastBalance_data[$parentHead]['data'][$acHead]))
  1182.                                         $lastBalanceDataByAcHead[$acHead]['balance'] = $lastBalance_data[$parentHead]['data'][$acHead]['end_balance']['balance'];
  1183.                                     else
  1184.                                         $lastBalanceDataByAcHead[$acHead]['balance'] = 0;
  1185.                                 } else
  1186.                                     $lastBalanceDataByAcHead[$acHead]['balance'] = 0;
  1187.                                 if (!isset($thisBalanceDataByClientType[$clientTypesOfHeads[$acHead]]))
  1188.                                     $thisBalanceDataByClientType[$clientTypesOfHeads[$acHead]] = $headData['end_balance']['balance'];
  1189.                                 else
  1190.                                     $thisBalanceDataByClientType[$clientTypesOfHeads[$acHead]] += $headData['end_balance']['balance'];
  1191.                                 if (!isset($lastBalanceDataByClientType[$clientTypesOfHeads[$acHead]]))
  1192.                                     $lastBalanceDataByClientType[$clientTypesOfHeads[$acHead]] = 0;
  1193.                                 else
  1194.                                     $lastBalanceDataByClientType[$clientTypesOfHeads[$acHead]] += $lastBalance_data[$parentHead]['data'][$acHead]['end_balance']['balance'];
  1195.                                 $skipHeadIds[] = $acHead;
  1196.                             }
  1197.                         }
  1198.                         foreach ($lastBalance_data as $parentHead => $balanceData) {
  1199.                             foreach ($balanceData['data'] as $acHead => $headData) {
  1200.                                 if (in_array($acHead$skipHeadIds))
  1201.                                     continue;
  1202.                                 if (!in_array($acHead$acHeadList))
  1203.                                     continue;
  1204.                                 //                                if ($headData['head_level'] > 4)
  1205.                                 //                                    continue;
  1206.                                 $lastBalanceDataByAcHead[$acHead]['balance'] = $headData['end_balance']['balance'];
  1207.                                 if (isset($thisBalance_data[$parentHead])) {
  1208.                                     if (isset($thisBalance_data[$parentHead]['data'][$acHead]))
  1209.                                         $thisBalanceDataByAcHead[$acHead]['balance'] = $thisBalance_data[$parentHead]['data'][$acHead]['end_balance']['balance'];
  1210.                                     else
  1211.                                         $thisBalanceDataByAcHead[$acHead]['balance'] = 0;
  1212.                                 } else
  1213.                                     $thisBalanceDataByAcHead[$acHead]['balance'] = 0;
  1214.                                 if (!isset($lastBalanceDataByClientType[$clientTypesOfHeads[$acHead]]))
  1215.                                     $lastBalanceDataByClientType[$clientTypesOfHeads[$acHead]] = $headData['end_balance']['balance'];
  1216.                                 else
  1217.                                     $lastBalanceDataByClientType[$clientTypesOfHeads[$acHead]] += $headData['end_balance']['balance'];
  1218.                                 if (!isset($thisBalanceDataByClientType[$clientTypesOfHeads[$acHead]]))
  1219.                                     $thisBalanceDataByClientType[$clientTypesOfHeads[$acHead]] = 0;
  1220.                                 $skipHeadIds[] = $acHead;
  1221.                             }
  1222.                         }
  1223.                         $thisReportData = array(
  1224.                             //                            'accountsHeadList' => $acHeadList,
  1225.                             //                            'thisBalance_data' => $thisBalance_data,
  1226.                             //                            'confirmedHeadList' => $skipHeadIds,
  1227.                             //                            'acHeadDataById' => $acHeadDataById,
  1228.                             'thisBalance_data' => $thisBalance_data,
  1229.                             'lastBalance_data' => $lastBalance_data,
  1230.                             'thisBalanceDataByAcHead' => $thisBalanceDataByAcHead,
  1231.                             'lastBalanceDataByAcHead' => $lastBalanceDataByAcHead,
  1232.                             'clientTypeListArray' => $clientTypeListArray,
  1233.                             'thisBalanceDataByClientType' => $thisBalanceDataByClientType,
  1234.                             'lastBalanceDataByClientType' => $lastBalanceDataByClientType,
  1235.                         );
  1236.                         $data['receivable_position'][$app_company_index] = $thisReportData;
  1237.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  1238.                     }
  1239.                     //Sales Position
  1240.                     if (in_array('sales_position'$reportsToGet)) {
  1241.                         $acHeadList = [];
  1242.                         $companyId explode('_'$app_company_index)[1];
  1243.                         $acHeadDataById = [];
  1244.                         $thisBalanceDataByClientType = [];
  1245.                         $lastBalanceDataByClientType = [];
  1246.                         $get_sql "SELECT sum(sales_invoice.invoice_amount) sales_amount,client_type.client_type_id, client_type.name, acc_clients.client_id, acc_clients.type
  1247.   FROM sales_invoice
  1248.   join acc_clients on acc_clients.client_id=sales_invoice.client_id
  1249.   join client_type on acc_clients.type=client_type.client_type_id
  1250.    WHERE sales_invoice.company_id=" $companyId " AND sales_invoice.approved=1
  1251.                           AND sales_invoice_date between '" $thisPeriodStartDate " 00:00:00' and '" $thisPeriodEndDate " 23:59:59.999'
  1252.                           GROUP BY client_type.client_type_id
  1253.                           ";
  1254.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1255.                         
  1256.                         $entries $stmt;
  1257.                         $clientTypes = [];
  1258.                         $clientTypeNames = [];
  1259.                         $get_sql_1 $get_sql;
  1260.                         foreach ($entries as $entry) {
  1261.                             $has_payments 1;
  1262.                             $thisBalanceDataByClientType[$entry['client_type_id']] = $entry;
  1263.                             $lastBalanceDataByClientType[$entry['client_type_id']]['sales_amount'] = 0//just for the lulz
  1264.                             if (!in_array($entry['client_type_id'], $clientTypes)) {
  1265.                                 $clientTypes[] = $entry['client_type_id'];
  1266.                                 $clientTypeNames[$entry['client_type_id']] = $entry['name'];
  1267.                             }
  1268.                         }
  1269.                         $get_sql "SELECT sum(sales_invoice.invoice_amount) sales_amount,client_type.client_type_id, client_type.name, acc_clients.client_id, acc_clients.type
  1270.   FROM sales_invoice
  1271.   join acc_clients on acc_clients.client_id=sales_invoice.client_id
  1272.   join client_type on acc_clients.type=client_type.client_type_id
  1273.    WHERE sales_invoice.company_id=" $companyId " AND sales_invoice.approved=1
  1274.                           AND sales_invoice_date between '" $lastPeriodStartDate " 00:00:00' and '" $lastPeriodEndDate " 23:59:59.999'
  1275.                           GROUP BY client_type.client_type_id
  1276.                           ";
  1277.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1278.                         
  1279.                         $entries $stmt;
  1280.                         foreach ($entries as $entry) {
  1281.                             $has_payments 1;
  1282.                             $lastBalanceDataByClientType[$entry['client_type_id']] = $entry;
  1283.                             if (!isset($thisBalanceDataByClientType[$entry['client_type_id']]))
  1284.                                 $thisBalanceDataByClientType[$entry['client_type_id']]['sales_amount'] = 0//just for the lulz
  1285.                             if (!in_array($entry['client_type_id'], $clientTypes)) {
  1286.                                 $clientTypes[] = $entry['client_type_id'];
  1287.                                 $clientTypeNames[$entry['client_type_id']] = $entry['name'];
  1288.                             }
  1289.                         }
  1290.                         $skipHeadIds = [];
  1291.                         $thisReportData = array(
  1292.                             'clientTypes' => $clientTypes,
  1293.                             //                            'get_sql_1' => $get_sql_1,
  1294.                             //                            'get_sql' => $get_sql,
  1295.                             'clientTypeNames' => $clientTypeNames,
  1296.                             'thisBalanceDataByClientType' => $thisBalanceDataByClientType,
  1297.                             'lastBalanceDataByClientType' => $lastBalanceDataByClientType,
  1298.                         );
  1299.                         $data['sales_position'][$app_company_index] = $thisReportData;
  1300.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  1301.                     }
  1302.                     //Collection Position
  1303.                     if (in_array('collection_position'$reportsToGet)) {
  1304.                         $acHeadList = [];
  1305.                         $companyId explode('_'$app_company_index)[1];
  1306.                         $acHeadDataById = [];
  1307.                         $thisBalanceDataByClientType = [];
  1308.                         $lastBalanceDataByClientType = [];
  1309.                         $allocationSourceSql $this->buildAllocationAwareTransactionSourceSql(array(
  1310.                             'document_type' => 6,
  1311.                             'start_date' => $thisPeriodStartDate,
  1312.                             'end_date' => $thisPeriodEndDate,
  1313.                             'approved' => 1,
  1314.                             'ledger_hit' => 1,
  1315.                         ));
  1316.                         $get_sql "SELECT SUM(CASE WHEN alloc_rows.position = 'cr' THEN alloc_rows.allocation_amount ELSE 0 END) positive_amount,
  1317. SUM(CASE WHEN alloc_rows.position = 'dr' THEN alloc_rows.allocation_amount ELSE 0 END) negative_amount,client_type.client_type_id, client_type.name, acc_clients.client_id, acc_clients.type
  1318.  FROM " $allocationSourceSql " alloc_rows
  1319.    join acc_clients on acc_clients.accounts_head_id=alloc_rows.accounts_head_id or acc_clients.advance_head_id=alloc_rows.accounts_head_id
  1320.   join client_type on acc_clients.type=client_type.client_type_id
  1321.   WHERE acc_clients.company_id=" $companyId "
  1322.                               GROUP BY client_type.client_type_id";
  1323.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1324.                         
  1325.                         $entries $stmt;
  1326.                         $clientTypes = [];
  1327.                         $clientTypeNames = [];
  1328.                         foreach ($entries as $entry) {
  1329.                             $has_payments 1;
  1330.                             $thisBalanceDataByClientType[$entry['client_type_id']] = $entry;
  1331.                             $lastBalanceDataByClientType[$entry['client_type_id']]['collection_amount'] = 0//just for the lulz
  1332.                             $thisBalanceDataByClientType[$entry['client_type_id']]['collection_amount'] = $entry['positive_amount'] - $entry['negative_amount'];
  1333.                             if (!in_array($entry['client_type_id'], $clientTypes)) {
  1334.                                 $clientTypes[] = $entry['client_type_id'];
  1335.                                 $clientTypeNames[$entry['client_type_id']] = $entry['name'];
  1336.                             }
  1337.                         }
  1338.                         $allocationSourceSql $this->buildAllocationAwareTransactionSourceSql(array(
  1339.                             'document_type' => 6,
  1340.                             'start_date' => $lastPeriodStartDate,
  1341.                             'end_date' => $lastPeriodEndDate,
  1342.                             'approved' => 1,
  1343.                             'ledger_hit' => 1,
  1344.                         ));
  1345.                         $get_sql "SELECT SUM(CASE WHEN alloc_rows.position = 'cr' THEN alloc_rows.allocation_amount ELSE 0 END) positive_amount,
  1346. SUM(CASE WHEN alloc_rows.position = 'dr' THEN alloc_rows.allocation_amount ELSE 0 END) negative_amount,client_type.client_type_id, client_type.name, acc_clients.client_id, acc_clients.type
  1347.  FROM " $allocationSourceSql " alloc_rows
  1348.    join acc_clients on acc_clients.accounts_head_id=alloc_rows.accounts_head_id or acc_clients.advance_head_id=alloc_rows.accounts_head_id
  1349.   join client_type on acc_clients.type=client_type.client_type_id
  1350.   WHERE acc_clients.company_id=" $companyId "
  1351.                               GROUP BY client_type.client_type_id";
  1352.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1353.                         
  1354.                         $entries $stmt;
  1355.                         foreach ($entries as $entry) {
  1356.                             $has_payments 1;
  1357.                             $lastBalanceDataByClientType[$entry['client_type_id']] = $entry;
  1358.                             $lastBalanceDataByClientType[$entry['client_type_id']]['collection_amount'] = $entry['positive_amount'] - $entry['negative_amount'];
  1359.                             if (!isset($thisBalanceDataByClientType[$entry['client_type_id']]))
  1360.                                 $thisBalanceDataByClientType[$entry['client_type_id']]['collection_amount'] = 0//just for the lulz
  1361.                             if (!in_array($entry['client_type_id'], $clientTypes)) {
  1362.                                 $clientTypes[] = $entry['client_type_id'];
  1363.                                 $clientTypeNames[$entry['client_type_id']] = $entry['name'];
  1364.                             }
  1365.                         }
  1366.                         $skipHeadIds = [];
  1367.                         $thisReportData = array(
  1368.                             'clientTypes' => $clientTypes,
  1369.                             'clientTypeNames' => $clientTypeNames,
  1370.                             'thisBalanceDataByClientType' => $thisBalanceDataByClientType,
  1371.                             'lastBalanceDataByClientType' => $lastBalanceDataByClientType,
  1372.                         );
  1373.                         $data['collection_position'][$app_company_index] = $thisReportData;
  1374.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  1375.                     }
  1376.                     //Return Position
  1377.                     if (in_array('market_return_position'$reportsToGet)) {
  1378.                         $acHeadList = [];
  1379.                         $companyId explode('_'$app_company_index)[1];
  1380.                         $acHeadDataById = [];
  1381.                         $thisBalanceDataByClientType = [];
  1382.                         $lastBalanceDataByClientType = [];
  1383.                         $get_sql "SELECT sum(irr_item.received_total_sales_price) return_amount,client_type.client_type_id, client_type.name, acc_clients.client_id, acc_clients.type
  1384.   FROM irr_item
  1385.   join item_received_replacement on item_received_replacement.irr_id=irr_item.irr_id
  1386.   join acc_clients on acc_clients.client_id=item_received_replacement.client_id
  1387.   join client_type on acc_clients.type=client_type.client_type_id
  1388.    WHERE item_received_replacement.company_id=" $companyId " AND item_received_replacement.approved=1
  1389.                           AND item_received_replacement.irr_date between '" $thisPeriodStartDate " 00:00:00' and '" $thisPeriodEndDate " 23:59:59.999'
  1390.                           GROUP BY client_type.client_type_id
  1391.                           ";
  1392.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1393.                         
  1394.                         $entries $stmt;
  1395.                         $clientTypes = [];
  1396.                         $clientTypeNames = [];
  1397.                         $get_sql_1 $get_sql;
  1398.                         foreach ($entries as $entry) {
  1399.                             $has_payments 1;
  1400.                             $thisBalanceDataByClientType[$entry['client_type_id']] = $entry;
  1401.                             $lastBalanceDataByClientType[$entry['client_type_id']]['return_amount'] = 0//just for the lulz
  1402.                             if (!in_array($entry['client_type_id'], $clientTypes)) {
  1403.                                 $clientTypes[] = $entry['client_type_id'];
  1404.                                 $clientTypeNames[$entry['client_type_id']] = $entry['name'];
  1405.                             }
  1406.                         }
  1407.                         $get_sql "SELECT sum(irr_item.received_total_sales_price) return_amount,client_type.client_type_id, client_type.name, acc_clients.client_id, acc_clients.type
  1408.   FROM irr_item
  1409.   join item_received_replacement on item_received_replacement.irr_id=irr_item.irr_id
  1410.   join acc_clients on acc_clients.client_id=item_received_replacement.client_id
  1411.   join client_type on acc_clients.type=client_type.client_type_id
  1412.    WHERE item_received_replacement.company_id=" $companyId " AND item_received_replacement.approved=1
  1413.                           AND item_received_replacement.irr_date between '" $lastPeriodStartDate " 00:00:00' and '" $lastPeriodEndDate " 23:59:59.999'
  1414.                           GROUP BY client_type.client_type_id
  1415.                           ";
  1416.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1417.                         
  1418.                         $entries $stmt;
  1419.                         foreach ($entries as $entry) {
  1420.                             $has_payments 1;
  1421.                             $lastBalanceDataByClientType[$entry['client_type_id']] = $entry;
  1422.                             if (!isset($thisBalanceDataByClientType[$entry['client_type_id']]))
  1423.                                 $thisBalanceDataByClientType[$entry['client_type_id']]['return_amount'] = 0//just for the lulz
  1424.                             if (!in_array($entry['client_type_id'], $clientTypes)) {
  1425.                                 $clientTypes[] = $entry['client_type_id'];
  1426.                                 $clientTypeNames[$entry['client_type_id']] = $entry['name'];
  1427.                             }
  1428.                         }
  1429.                         $skipHeadIds = [];
  1430.                         $thisReportData = array(
  1431.                             'clientTypes' => $clientTypes,
  1432.                             //                            'get_sql_1' => $get_sql_1,
  1433.                             //                            'get_sql' => $get_sql,
  1434.                             'clientTypeNames' => $clientTypeNames,
  1435.                             'thisBalanceDataByClientType' => $thisBalanceDataByClientType,
  1436.                             'lastBalanceDataByClientType' => $lastBalanceDataByClientType,
  1437.                         );
  1438.                         $data['market_return_position'][$app_company_index] = $thisReportData;
  1439.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  1440.                     }
  1441.                     //order and client count
  1442.                     if (in_array('order_and_client_count'$reportsToGet)) {
  1443.                         $acHeadList = [];
  1444.                         $companyId explode('_'$app_company_index)[1];
  1445.                         $acHeadDataById = [];
  1446.                         $thisBalanceDataByAcHead = [];
  1447.                         $lastBalanceDataByAcHead = [];
  1448.                         $today = new \DateTime();
  1449.                         $get_sql "SELECT count(sales_order_id) total_so_count, sum(so_amount) total_so_amount, sum(invoice_amount) total_invoice_amount FROM sales_order WHERE sales_order.company_id=" $companyId " and  sales_order.sales_order_date between '" $thisPeriodStartDate " 00:00:00' and '" $thisPeriodEndDate " 23:59:59.999' ";
  1450.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1451.                         
  1452.                         $entries1 $stmt;
  1453.                         $get_sql "SELECT count(client_id) total_clients FROM acc_clients WHERE acc_clients.company_id=" $companyId;
  1454.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1455.                         
  1456.                         $entries2 $stmt;
  1457.                         $currCompanyData Company::getCompanyData($em$session->get(UserConstants::USER_COMPANY_ID$companyId));
  1458.                         $allocationSourceSql $this->buildAllocationAwareTransactionSourceSql(array(
  1459.                             'document_type' => 6,
  1460.                             'company_id' => $companyId,
  1461.                             'start_date' => $thisPeriodStartDate,
  1462.                             'end_date' => $thisPeriodEndDate,
  1463.                             'approved' => 1,
  1464.                             'ledger_hit' => 1,
  1465.                         ));
  1466.                         $get_sql "SELECT SUM(CASE WHEN alloc_rows.position = 'cr' THEN alloc_rows.allocation_amount ELSE ((-1)*alloc_rows.allocation_amount) END) total_collection_amount, alloc_rows.document_hash FROM " $allocationSourceSql " alloc_rows
  1467.                         join acc_clients on acc_clients.accounts_head_id=alloc_rows.accounts_head_id or acc_clients.advance_head_id=alloc_rows.accounts_head_id
  1468.                         WHERE acc_clients.company_id=" $companyId " ";
  1469.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1470.                         
  1471.                         $entries3 $stmt;
  1472.                         //
  1473.                         //                        $get_sql = "SELECT (select  c.balance last_balance from inv_closing_balance c
  1474.                         //where c.product_id=a.product_id and c.warehouse_id=a.warehouse_id and c.action_tag_id=a.action_tag_id order by date desc limit 1) stock_amount
  1475.                         //from inv_closing_balance a
  1476.                         //                        where a.warehouse_id in (select distinct id from warehouse
  1477.                         //                        WHERE  warehouse.company_id=" . $companyId . ") and  a.date between '" . $thisPeriodStartDate . " 00:00:00' and '" . $thisPeriodEndDate . " 23:59:59.999' ";
  1478.                         $get_sql "SELECT a.* , (select  c.balance last_balance from inv_closing_balance c
  1479. where date <='" $thisPeriodEndDate " 00:00:00' and c.product_id=a.product_id and c.warehouse_id=a.warehouse_id and c.action_tag_id=a.action_tag_id order by date desc limit 1) last_balance
  1480. from inv_closing_balance a
  1481. where a.warehouse_id in (select distinct id from warehouse
  1482.                       WHERE  warehouse.company_id=" $companyId ") ";
  1483.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1484.                         
  1485.                         $entries4 $stmt;
  1486.                         $currCompanyData Company::getCompanyData($em$session->get(UserConstants::USER_COMPANY_ID$companyId));
  1487.                         $total_stock_amount 0;
  1488.                         foreach ($entries4 as $ent) {
  1489.                             $total_stock_amount += $ent['last_balance'];
  1490.                         }
  1491.                         $thisReportData = array(
  1492.                             //                            'total_stock_amount' => empty($entries3) ? 0 : $entries4[0]['total_stock_amount'],
  1493.                             'total_stock_amount' => $total_stock_amount,
  1494.                             'total_collection_amount' => empty($entries3) ? $entries3[0]['total_collection_amount'],
  1495.                             'total_so_count' => empty($entries1) ? $entries1[0]['total_so_count'],
  1496.                             'total_so_amount' => empty($entries1) ? $entries1[0]['total_so_amount'],
  1497.                             'total_invoice_amount' => empty($entries1) ? $entries1[0]['total_invoice_amount'],
  1498.                             'total_receivable' => $currCompanyData->getReceivable(),
  1499.                             'total_payable' => $currCompanyData->getPayable(),
  1500.                             'total_clients' => empty($entries2) ? $entries2[0]['total_clients'],
  1501.                         );
  1502.                         $data['order_and_client_count'][$app_company_index] = $thisReportData;
  1503.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  1504.                     }
  1505.                     //Inventory Position
  1506.                     if (in_array('inventory_position'$reportsToGet)) {
  1507.                         $acHeadList = [];
  1508.                         $companyId explode('_'$app_company_index)[1];
  1509.                         $acHeadDataById = [];
  1510.                         $thisBalanceDataByActionTag = [];
  1511.                         $lastBalanceDataByActionTag = [];
  1512.                         $warehouseList Inventory::warehouse_action_list($em$companyId$method 'object');
  1513.                         $get_sql "SELECT a.* , (select  c.balance last_balance from inv_closing_balance c
  1514. where date <='" $thisPeriodEndDate " 00:00:00' and c.product_id=a.product_id and c.warehouse_id=a.warehouse_id and c.action_tag_id=a.action_tag_id order by date desc limit 1) last_balance
  1515. from inv_closing_balance a
  1516. where a.warehouse_id in (select distinct id from warehouse
  1517.                        WHERE  warehouse.company_id=" $companyId ") ";
  1518.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1519.                         
  1520.                         $entries $stmt;
  1521.                         $confirmed_action_ids = [];
  1522.                         $confirmed_action_names = [];
  1523.                         $get_sql_1 $get_sql;
  1524.                         foreach ($entries as $entry) {
  1525.                             $has_payments 1;
  1526.                             if (isset($thisBalanceDataByActionTag[$entry['action_tag_id']]))
  1527.                                 $thisBalanceDataByActionTag[$entry['action_tag_id']]['inventory_amount'] += $entry['last_balance'];
  1528.                             else
  1529.                                 $thisBalanceDataByActionTag[$entry['action_tag_id']]['inventory_amount'] = $entry['last_balance'];
  1530.                             if (!isset($lastBalanceDataByActionTag[$entry['action_tag_id']]))
  1531.                                 $lastBalanceDataByActionTag[$entry['action_tag_id']]['inventory_amount'] = 0;
  1532.                             if (!in_array($entry['action_tag_id'], $confirmed_action_ids)) {
  1533.                                 $confirmed_action_ids[] = $entry['action_tag_id'];
  1534.                                 $confirmed_action_names[$entry['action_tag_id']] = $warehouseList[$entry['action_tag_id']]['name'];
  1535.                             }
  1536.                         }
  1537.                         $get_sql "SELECT a.* , (select  c.balance last_balance from inv_closing_balance c
  1538. where date <='" $lastPeriodEndDate " 00:00:00' and c.product_id=a.product_id and c.warehouse_id=a.warehouse_id and c.action_tag_id=a.action_tag_id order by date desc limit 1) last_balance
  1539. from inv_closing_balance a
  1540. where a.warehouse_id in (select distinct id from warehouse
  1541.                        WHERE  warehouse.company_id=" $companyId ") ";
  1542.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1543.                         
  1544.                         $entries $stmt;
  1545.                         foreach ($entries as $entry) {
  1546.                             $has_payments 1;
  1547.                             if (isset($lastBalanceDataByActionTag[$entry['action_tag_id']]))
  1548.                                 $lastBalanceDataByActionTag[$entry['action_tag_id']]['inventory_amount'] += $entry['last_balance'];
  1549.                             else
  1550.                                 $lastBalanceDataByActionTag[$entry['action_tag_id']]['inventory_amount'] = $entry['last_balance'];
  1551.                             if (!isset($thisBalanceDataByActionTag[$entry['action_tag_id']]))
  1552.                                 $thisBalanceDataByActionTag[$entry['action_tag_id']]['inventory_amount'] = 0;
  1553.                             if (!in_array($entry['action_tag_id'], $confirmed_action_ids)) {
  1554.                                 $confirmed_action_ids[] = $entry['action_tag_id'];
  1555.                                 $confirmed_action_names[$entry['action_tag_id']] = $warehouseList[$entry['action_tag_id']]['name'];
  1556.                             }
  1557.                         }
  1558.                         $skipHeadIds = [];
  1559.                         $thisReportData = array(
  1560.                             //                            'clientTypes' => $clientTypes,
  1561.                             //                            'get_sql_1' => $get_sql_1,
  1562.                             //                            'get_sql' => $get_sql,
  1563.                             'confirmed_action_ids' => $confirmed_action_ids,
  1564.                             'confirmed_action_names' => $confirmed_action_names,
  1565.                             'thisBalanceDataByActionTag' => $thisBalanceDataByActionTag,
  1566.                             'lastBalanceDataByActionTag' => $lastBalanceDataByActionTag,
  1567.                         );
  1568.                         $data['inventory_position'][$app_company_index] = $thisReportData;
  1569.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  1570.                     }
  1571.                     //Production Position
  1572.                     if (in_array('production_position'$reportsToGet)) {
  1573.                         $acHeadList = [];
  1574.                         $companyId explode('_'$app_company_index)[1];
  1575.                         $acHeadDataById = [];
  1576.                         $thisBalanceDataByIgId = [];
  1577.                         $lastBalanceDataByIgId = [];
  1578.                         $itemGroups = [];
  1579.                         $itemGroupNames = [];
  1580.                         $get_sql "SELECT sum((case WHEN inv_products.curr_sales_price!=0 then inv_products.curr_sales_price else inv_products.curr_purchase_price END )*production_entry_item.produced_qty) production_amount,inv_item_group.id item_group_id ,inv_item_group.name item_group_name ,inv_products.id product_id
  1581.   FROM production_entry_item
  1582.   join production on production_entry_item.production_id=production.production_id
  1583.   join inv_products on production_entry_item.product_id=inv_products.id
  1584.   join inv_item_group on inv_item_group.id=inv_products.ig_id
  1585.    WHERE production.company_id=" $companyId " AND production.approved=1
  1586.                           AND production.production_date between '" $thisPeriodStartDate " 00:00:00' and '" $thisPeriodEndDate " 23:59:59.999'
  1587.                           GROUP BY inv_item_group.id
  1588.                           ";
  1589.                         //                        $get_sql = "SELECT sum(product_mrp.average_price*production_entry_item.produced_qty) production_amount,inv_item_group.id item_group_id ,inv_item_group.name item_group_name ,inv_products.id product_id
  1590.                         //  FROM production_entry_item
  1591.                         //  join production on production_entry_item.production_id=production.production_id
  1592.                         //  join inv_products on production_entry_item.product_id=inv_products.id
  1593.                         //  join product_mrp on production_entry_item.product_id=product_mrp.product_id
  1594.                         //  join inv_item_group on inv_item_group.id=inv_products.ig_id
  1595.                         //   WHERE production.company_id=" . $companyId . " AND production.approved=1
  1596.                         //                          AND production.production_date between '" . $thisPeriodStartDate . " 00:00:00' and '" . $thisPeriodEndDate . " 23:59:59.999'
  1597.                         //                          GROUP BY inv_item_group.id
  1598.                         //                          ";
  1599.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1600.                         
  1601.                         $entries $stmt;
  1602.                         $get_sql_1 $get_sql;
  1603.                         foreach ($entries as $entry) {
  1604.                             $has_payments 1;
  1605.                             $thisBalanceDataByIgId[$entry['item_group_id']] = $entry;
  1606.                             $lastBalanceDataByIgId[$entry['item_group_id']]['production_amount'] = 0//just for the lulz
  1607.                             if (!in_array($entry['item_group_id'], $clientTypes)) {
  1608.                                 $itemGroups[] = $entry['item_group_id'];
  1609.                                 $itemGroupNames[$entry['item_group_id']] = $entry['item_group_name'];
  1610.                             }
  1611.                         }
  1612.                         $get_sql "SELECT sum(production_entry_item.price*production_entry_item.produced_qty) production_amount,inv_item_group.id item_group_id ,inv_item_group.name item_group_name ,inv_products.id product_id
  1613.   FROM production_entry_item
  1614.   join production on production_entry_item.production_id=production.production_id
  1615.   join inv_products on production_entry_item.product_id=inv_products.id
  1616.   join inv_item_group on inv_item_group.id=inv_products.ig_id
  1617.    WHERE production.company_id=" $companyId " AND production.approved=1
  1618.                           AND production.production_date between '" $lastPeriodStartDate " 00:00:00' and '" $lastPeriodEndDate " 23:59:59.999'
  1619.                           GROUP BY inv_item_group.id
  1620.                           ";
  1621.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1622.                         
  1623.                         $entries $stmt;
  1624.                         foreach ($entries as $entry) {
  1625.                             $has_payments 1;
  1626.                             $lastBalanceDataByIgId[$entry['item_group_id']] = $entry;
  1627.                             if (!isset($thisBalanceDataByIgId[$entry['item_group_id']]))
  1628.                                 $thisBalanceDataByIgId[$entry['item_group_id']]['production_amount'] = 0//just for the lulz
  1629.                             if (!in_array($entry['item_group_id'], $clientTypes)) {
  1630.                                 $itemGroups[] = $entry['item_group_id'];
  1631.                                 $itemGroupNames[$entry['item_group_id']] = $entry['item_group_name'];
  1632.                             }
  1633.                         }
  1634.                         $skipHeadIds = [];
  1635.                         $thisReportData = array(
  1636.                             'itemGroups' => $itemGroups,
  1637.                             //                            'get_sql_1' => $get_sql_1,
  1638.                             //                            'get_sql' => $get_sql,
  1639.                             'itemGroupNames' => $itemGroupNames,
  1640.                             'thisBalanceDataByIgId' => $thisBalanceDataByIgId,
  1641.                             'lastBalanceDataByIgId' => $lastBalanceDataByIgId,
  1642.                         );
  1643.                         $data['production_position'][$app_company_index] = $thisReportData;
  1644.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  1645.                     }
  1646.                     //Top Products
  1647.                     if (in_array('top_selling_item_position'$reportsToGet)) {
  1648.                         $acHeadList = [];
  1649.                         $companyId explode('_'$app_company_index)[1];
  1650.                         $acHeadDataById = [];
  1651.                         $thisBalanceDataByRelId = [];
  1652.                         $lastBalanceDataByRelId = [];
  1653.                         $clientIds = [];
  1654.                         $clientNames = [];
  1655.                         $productIds = [];
  1656.                         $productNames = [];
  1657.                         $get_sql "SELECT sum(sales_invoice_item.qty*sales_invoice_item.current_purchase_price) sales_amount, inv_products.id product_id, inv_products.name product_name, acc_clients.client_id, acc_clients.type
  1658.   FROM sales_invoice_item
  1659.   join sales_invoice on sales_invoice_item.sales_invoice_id=sales_invoice.sales_invoice_id
  1660.   join inv_products on sales_invoice_item.product_id=inv_products.id
  1661.   join acc_clients on acc_clients.client_id=sales_invoice.client_id
  1662.    WHERE sales_invoice.company_id=" $companyId " AND sales_invoice.approved=1
  1663.                           AND sales_invoice_date between '" $thisPeriodStartDate " 00:00:00' and '" $thisPeriodEndDate " 23:59:59.999'
  1664.                           GROUP BY sales_invoice_item.product_id
  1665.                           ORDER BY sales_amount DESC
  1666.                           LIMIT 10
  1667.                           ";
  1668.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1669.                         
  1670.                         $entries $stmt;
  1671.                         $get_sql_1 $get_sql;
  1672.                         for ($k 0$k 10$k++) {
  1673.                             $has_payments 1;
  1674.                             if (!isset($entries[$k]))
  1675.                                 $entries[$k] = array(
  1676.                                     'sales_amount' => '',
  1677.                                     'product_name' => '',
  1678.                                     'client_name' => '',
  1679.                                 );
  1680.                             $has_payments 1;
  1681.                             $thisBalanceDataByRelId[$k] = $entries[$k];
  1682.                         }
  1683.                         $get_sql "SELECT sum(sales_invoice_item.qty*sales_invoice_item.current_purchase_price) sales_amount, inv_products.id product_id, inv_products.name product_name, acc_clients.client_id, acc_clients.type
  1684.   FROM sales_invoice_item
  1685.   join sales_invoice on sales_invoice_item.sales_invoice_id=sales_invoice.sales_invoice_id
  1686.   join inv_products on sales_invoice_item.product_id=inv_products.id
  1687.   join acc_clients on acc_clients.client_id=sales_invoice.client_id
  1688.    WHERE sales_invoice.company_id=" $companyId " AND sales_invoice.approved=1
  1689.                           AND sales_invoice_date between '" $lastPeriodStartDate " 00:00:00' and '" $lastPeriodEndDate " 23:59:59.999'
  1690.                           GROUP BY sales_invoice_item.product_id
  1691.                           ORDER BY sales_amount DESC
  1692.                           LIMIT 10
  1693.                           ";
  1694.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1695.                         
  1696.                         $entries $stmt;
  1697.                         for ($k 0$k 10$k++) {
  1698.                             $has_payments 1;
  1699.                             if (!isset($entries[$k]))
  1700.                                 $entries[$k] = array(
  1701.                                     'sales_amount' => '',
  1702.                                     'product_name' => '',
  1703.                                     'client_name' => '',
  1704.                                 );
  1705.                             $lastBalanceDataByRelId[$k] = $entries[$k];
  1706.                         }
  1707.                         $skipHeadIds = [];
  1708.                         $thisReportData = array(
  1709.                             //                            'clientTypes' => $clientTypes,
  1710.                             ////                            'get_sql_1' => $get_sql_1,
  1711.                             ////                            'get_sql' => $get_sql,
  1712.                             //                            'clientTypeNames' => $clientTypeNames,
  1713.                             'thisBalanceDataByRelId' => $thisBalanceDataByRelId,
  1714.                             'lastBalanceDataByRelId' => $lastBalanceDataByRelId,
  1715.                         );
  1716.                         $data['top_selling_item_position'][$app_company_index] = $thisReportData;
  1717.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  1718.                     }
  1719.                     //Top Products
  1720.                     if (in_array('top_selling_client_position'$reportsToGet)) {
  1721.                         $acHeadList = [];
  1722.                         $companyId explode('_'$app_company_index)[1];
  1723.                         $acHeadDataById = [];
  1724.                         $thisBalanceDataByRelId = [];
  1725.                         $lastBalanceDataByRelId = [];
  1726.                         $clientIds = [];
  1727.                         $clientNames = [];
  1728.                         $productIds = [];
  1729.                         $productNames = [];
  1730.                         $get_sql "SELECT sum(sales_invoice.invoice_amount) sales_amount,  acc_clients.client_id, acc_clients.client_name client_name
  1731.   FROM sales_invoice
  1732.   join acc_clients on acc_clients.client_id=sales_invoice.client_id
  1733.    WHERE sales_invoice.company_id=" $companyId " AND sales_invoice.approved=1
  1734.                           AND sales_invoice_date between '" $thisPeriodStartDate " 00:00:00' and '" $thisPeriodEndDate " 23:59:59.999'
  1735.                           GROUP BY sales_invoice.client_id
  1736.                           ORDER BY sales_amount DESC
  1737.                           LIMIT 10
  1738.                           ";
  1739.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1740.                         
  1741.                         $entries $stmt;
  1742.                         $get_sql_1 $get_sql;
  1743.                         for ($k 0$k 10$k++) {
  1744.                             $has_payments 1;
  1745.                             if (!isset($entries[$k]))
  1746.                                 $entries[$k] = array(
  1747.                                     'sales_amount' => '',
  1748.                                     'product_name' => '',
  1749.                                     'client_name' => '',
  1750.                                 );
  1751.                             $has_payments 1;
  1752.                             $thisBalanceDataByRelId[$k] = $entries[$k];
  1753.                         }
  1754.                         $get_sql "SELECT sum(sales_invoice.invoice_amount) sales_amount,  acc_clients.client_id, acc_clients.client_name client_name
  1755.   FROM sales_invoice
  1756.   join acc_clients on acc_clients.client_id=sales_invoice.client_id
  1757.    WHERE sales_invoice.company_id=" $companyId " AND sales_invoice.approved=1
  1758.                           AND sales_invoice_date between '" $lastPeriodStartDate " 00:00:00' and '" $lastPeriodEndDate " 23:59:59.999'
  1759.                           GROUP BY sales_invoice.client_id
  1760.                           ORDER BY sales_amount DESC
  1761.                           LIMIT 10
  1762.                           ";
  1763.                         $stmt $em->getConnection()->fetchAllAssociative($get_sql);
  1764.                         
  1765.                         $entries $stmt;
  1766.                         for ($k 0$k 10$k++) {
  1767.                             $has_payments 1;
  1768.                             if (!isset($entries[$k]))
  1769.                                 $entries[$k] = array(
  1770.                                     'sales_amount' => '',
  1771.                                     'product_name' => '',
  1772.                                     'client_name' => '',
  1773.                                 );
  1774.                             $lastBalanceDataByRelId[$k] = $entries[$k];
  1775.                         }
  1776.                         $skipHeadIds = [];
  1777.                         $thisReportData = array(
  1778.                             //                            'clientTypes' => $clientTypes,
  1779.                             ////                            'get_sql_1' => $get_sql_1,
  1780.                             ////                            'get_sql' => $get_sql,
  1781.                             //                            'clientTypeNames' => $clientTypeNames,
  1782.                             'thisBalanceDataByRelId' => $thisBalanceDataByRelId,
  1783.                             'lastBalanceDataByRelId' => $lastBalanceDataByRelId,
  1784.                         );
  1785.                         $data['top_selling_client_position'][$app_company_index] = $thisReportData;
  1786.                         //                    $companyListData[] = Company::getCompanyListWithImage($em);
  1787.                     }
  1788.                 }
  1789.             }
  1790.         }
  1791.         return new JsonResponse(
  1792.             array(
  1793.                 'success' => true,
  1794.                 'data' => $data,
  1795.                 'companyListData' => $companyListData,
  1796.                 'dataToConnectList' => $dataToConnectList,
  1797.                 'periodType' => $periodType,
  1798.                 'queriedReportsToGet' => $request->request->get('reportsToGet'),
  1799.                 'reportsToGet' => $reportsToGet,
  1800.                 'thisPeriodStartDate' => $thisPeriodStartDate,
  1801.                 'thisPeriodEndDate' => $thisPeriodEndDate,
  1802.                 'lastPeriodStartDate' => $lastPeriodStartDate,
  1803.                 'lastPeriodEndDate' => $lastPeriodEndDate,
  1804.                 'companyIdListByAppId' => $companyIdListByAppId,
  1805.                 'companyNameListByAppId' => $companyNameListByAppId,
  1806.                 'companyImageListByAppId' => $companyImageListByAppId,
  1807.                 'appIdList' => $appIdList,
  1808.             )
  1809.         );
  1810.     }
  1811.     public function indexAction(Request $request$cgHash '')
  1812.     {
  1813.         $session $request->getSession();
  1814.         $systemType $this->container->hasParameter('system_type') ? $this->container->getParameter('system_type') : '_ERP_';
  1815.         if ($systemType == '_ERP_') {
  1816.             //do nothing its default to dashboard index
  1817.         } else if ($systemType == '_BUDDYBEE_') {
  1818.             if ($cgHash != '')
  1819.                 $session->set('codeHash'$cgHash);
  1820.         }
  1821.         // Generic::debugMessage($session);
  1822.         $ROUTE_LIST json_decode($session->get(UserConstants::USER_ROUTE_LIST), true);
  1823.         if ($ROUTE_LIST == null)
  1824.             $ROUTE_LIST = [];
  1825.         $CurrentRoute $request->attributes->get('_route');
  1826.         if ($session->get(UserConstants::USER_ROUTE_LIST) == || in_array('management_dashboard'$ROUTE_LIST)) {
  1827.             // User is not authorized. send him to dashboard
  1828.             //                    $controller->addFlash(
  1829.             //                        'error',
  1830.             //                        'Sorry Couldnot insert Data.'
  1831.             //                    );
  1832.             //                    return $this->render('ApplicationBundle:pages/dashboard:advanced_management_dashboard.html.twig',
  1833.             if ($session->has('isMobile'))
  1834.                 if ($session->get('isMobile') == true) {
  1835.                     return $this->render(
  1836.                         '@Application/pages/dashboard/index_finance_mobile.html.twig',
  1837.                         array(
  1838.                             'page_title' => 'Finance Dashboard',
  1839.                             'dashboardDataForUser' => []
  1840.                         )
  1841.                     );
  1842.                 }
  1843.             return $this->render(
  1844.                 '@Application/pages/dashboard/advanced_management_dashboard.html.twig',
  1845.                 array(
  1846.                     'page_title' => 'Dashboard'
  1847.                 )
  1848.             );
  1849.         }
  1850.         if ($session->has('isMobile'))
  1851.             if ($session->get('isMobile') == true) {
  1852.                 if ($systemType == '_CENTRAL_') {
  1853.                     $defaultRoute 'central_landing';
  1854.                     return $this->redirectToRoute($defaultRoute);
  1855.                 }
  1856.                 elseif ($systemType == '_SOPHIA_') {
  1857.                     $defaultRoute 'sofia_dashboard_admin';
  1858.                     return $this->redirectToRoute($defaultRoute);
  1859.                 }else
  1860.                     return $this->render(
  1861.                         '@Application/pages/dashboard/index_finance_mobile.html.twig',
  1862.                         array(
  1863.                             'page_title' => 'Finance Dashboard',
  1864.                             'dashboardDataForUser' => []
  1865.                         )
  1866.                     );
  1867.             }
  1868.         else {
  1869.                 //check if user has a default route if yes redirect to it
  1870.                 if ($session->get(UserConstants::USER_TYPE) == UserConstants::USER_TYPE_SUPPLIER)
  1871.                     $defaultRoute 'supplier_dashboard';
  1872.                 else if ($session->get(UserConstants::USER_TYPE) == UserConstants::USER_TYPE_CLIENT)
  1873.                     $defaultRoute 'client_dashboard';
  1874.                 else if ($session->get(UserConstants::USER_TYPE) == UserConstants::USER_TYPE_APPLICANT) {
  1875.                     if ($systemType == '_CENTRAL_') {
  1876.                         $defaultRoute 'central_landing';
  1877.                     }
  1878.                     elseif ($systemType == '_SOPHIA_') {
  1879.                         $defaultRoute 'sofia_dashboard_admin';
  1880.                     } else
  1881.                         $defaultRoute 'applicant_dashboard';
  1882.                 } else
  1883.                     $defaultRoute $session->get(UserConstants::USER_DEFAULT_ROUTE);
  1884.                 //            if(in_array($defaultRoute, $ROUTE_LIST))
  1885.                 if ($defaultRoute != '' && $defaultRoute != null)
  1886.                     return $this->redirectToRoute($defaultRoute);
  1887.                 else
  1888.                     return $this->redirectToRoute('sales_dashboard');
  1889. //                return $this->render(
  1890. //                    'ApplicationBundle:pages/dashboard:index.html.twig',
  1891. //                    array(
  1892. //                        'page_title' => 'Dashboard',
  1893. //                        'allocation_filters' => [],
  1894. //                        'allocationFilters' => [],
  1895. //                        'allocation_tag_types' => [],
  1896. //                        'allocation_tag_values_by_type' => [],
  1897. //                        'project_list' => [],
  1898. //                        'branch_list' => [],
  1899. //                        'cost_centers' => []
  1900. //                    )
  1901. //                );
  1902.             }
  1903.     }
  1904.     public function indexSupplierAction(Request $request)
  1905.     {
  1906.         $session $request->getSession();
  1907.         $supplierId 3;
  1908.         if ($request->query->has('supplierId')) //for debug now
  1909.         {
  1910.             $session->set('supplierId'$request->query->get('supplierId'));
  1911.         }
  1912.         $supplierId $session->get('supplierId');  //////////////////////LATER
  1913.         $em $this->getDoctrine()->getManager();
  1914.         $companyId $this->getLoggedUserCompanyId($request);
  1915.         $userId $request->getSession()->get(UserConstants::USER_ID);
  1916.         $SD Supplier::GetSupplierProfileDetails($em$supplierId'SI');
  1917.         $dashboardDataForUser = [];
  1918.         return $this->render(
  1919.             '@Application/pages/dashboard/index_supplier.html.twig',
  1920.             array(
  1921.                 'page_title' => 'Supplier Dashboard',
  1922.                 'dashboardDataForUser' => $dashboardDataForUser,
  1923.                 'data' => $SD,
  1924.                 'igList' => Inventory::ItemGroupList($em$companyId)
  1925.             )
  1926.         );
  1927.     }
  1928.     public function indexClientAction(Request $request)
  1929.     {
  1930.         $session $request->getSession();
  1931.         $clientId 3;
  1932.         if ($request->query->has('clientId')) //for debug now
  1933.         {
  1934.             $session->set('clientId'$request->query->get('clientId'));
  1935.         }
  1936.         $clientId $session->get('clientId');  //////////////////////LATER
  1937.         $em $this->getDoctrine()->getManager();
  1938.         $companyId $this->getLoggedUserCompanyId($request);
  1939.         $userId $request->getSession()->get(UserConstants::USER_ID);
  1940.         $SD Client::GetClientProfileDetails($em$clientId'CI');
  1941.         $dashboardDataForUser = [];
  1942.         return $this->render(
  1943.             '@Application/pages/dashboard/index_client.html.twig',
  1944.             array(
  1945.                 'page_title' => 'Client Dashboard',
  1946.                 'dashboardDataForUser' => $dashboardDataForUser,
  1947.                 'data' => $SD,
  1948.                 'igList' => Inventory::ItemGroupList($em$companyId)
  1949.             )
  1950.         );
  1951.     }
  1952.     public function indexFinanceAction(Request $request)
  1953.     {
  1954.         $session $request->getSession();
  1955.         $dashboardDataForUser = [];
  1956.         $em $this->getDoctrine()->getManager();
  1957.         $companyId $this->getLoggedUserCompanyId($request);
  1958.         $userId $request->getSession()->get(UserConstants::USER_ID);
  1959.         $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  1960.             array(
  1961.                 'CompanyId' => $companyId,
  1962.                 'userId' => $userId,
  1963.                 'status' => GeneralConstant::ACTIVE
  1964.             ),
  1965.             array(
  1966.                 'sequence' => 'ASC'
  1967.             )
  1968.         );
  1969.         if (empty($dbQuery))   ///now get the defaults
  1970.             $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  1971.                 array(
  1972.                     'CompanyId' => $companyId,
  1973.                     //                    'userId'=>$userId,
  1974.                     'defaultBoxFlag' => 1,
  1975.                     'status' => GeneralConstant::ACTIVE
  1976.                 ),
  1977.                 array(
  1978.                     'sequence' => 'ASC'
  1979.                 )
  1980.             );
  1981.         foreach ($dbQuery as $entry) {
  1982.             $dashboardDataForUser[] = array(
  1983.                 'id' => $entry->getId(),
  1984.                 'widgetId' => $entry->getId(),
  1985.                 'widgetSequence' => $entry->getSequence(),
  1986.                 'widgetStatus' => $entry->getStatus(),
  1987.                 'widgetData' => json_decode($entry->getData(), true),
  1988.                 'defaultBoxFlag' => $entry->getDefaultBoxFlag(),
  1989.                 'widgetSizeTiny' => $entry->getSizeTiny(),
  1990.                 'widgetSizeSmall' => $entry->getSizeSmall(),
  1991.                 'widgetSizeMedium' => $entry->getSizeMedium(),
  1992.                 'widgetSizeLarge' => $entry->getSizeLarge(),
  1993.                 'refreshInterval' => $entry->getRefreshInterval(),
  1994.             );
  1995.         }
  1996.         if ($session->has('isMobile')) {
  1997.             if ($session->get('isMobile') == true) {
  1998.                 return $this->render(
  1999.                     '@Application/pages/dashboard/index_finance_mobile.html.twig',
  2000.                     array(
  2001.                         'page_title' => 'Finance Dashboard',
  2002.                         'dashboardDataForUser' => $dashboardDataForUser
  2003.                     )
  2004.                 );
  2005.             } else {
  2006.             }
  2007.         }
  2008.         return $this->render(
  2009.             '@Accounts/pages/finance_dashboard.html.twig',
  2010.             array(
  2011.                 'page_title' => 'Finance Dashboard',
  2012.                 'dashboardDataForUser' => $dashboardDataForUser,
  2013.                 'dashboardAnalytics' => $this->buildFinanceDashboardAnalytics($em)
  2014.             )
  2015.         );
  2016.     }
  2017.     /**
  2018.      * Lean, fail-safe analytics for the Finance cp-shell dashboard. Guarded scalar DQL â€”
  2019.      * a schema/tenant quirk degrades to 0 rather than 500-ing the dashboard.
  2020.      */
  2021.     private function buildFinanceDashboardAnalytics($em)
  2022.     {
  2023.         $scalar = function ($dql$params = []) use ($em) {
  2024.             try {
  2025.                 $v $em->createQuery($dql)->setParameters($params)->getSingleScalarResult();
  2026.                 return $v === null $v;
  2027.             } catch (\Throwable $e) {
  2028.                 return 0;
  2029.             }
  2030.         };
  2031.         $salesInv     = (int) $scalar("SELECT COUNT(i) FROM ApplicationBundle:SalesInvoice i WHERE (i.deleteFlag = 0 OR i.deleteFlag IS NULL)");
  2032.         $expenseInv   = (int) $scalar("SELECT COUNT(e) FROM ApplicationBundle:ExpenseInvoice e WHERE (e.deleteFlag = 0 OR e.deleteFlag IS NULL)");
  2033.         $banks        = (int) $scalar("SELECT COUNT(b) FROM ApplicationBundle:BankAccounts b");
  2034.         $salesPending = (int) $scalar("SELECT COUNT(i) FROM ApplicationBundle:SalesInvoice i WHERE i.approved <> :a AND (i.deleteFlag = 0 OR i.deleteFlag IS NULL)", ['a' => GeneralConstant::APPROVED]);
  2035.         $expPending   = (int) $scalar("SELECT COUNT(e) FROM ApplicationBundle:ExpenseInvoice e WHERE e.approved <> :a AND (e.deleteFlag = 0 OR e.deleteFlag IS NULL)", ['a' => GeneralConstant::APPROVED]);
  2036.         // â”€â”€ Money figures (outstanding + this-month), fail-safe â”€â”€
  2037.         // Receivable/Payable come from the GL (transactions Ã— each leg's FX rate to base), NOT the
  2038.         // invoice sub-ledger (i.dueAmount) nor the stored current_balance. Both of those drift when a
  2039.         // payment is booked as a journal/contra voucher instead of an invoice-linked receipt â€” verified
  2040.         // on a live tenant where the sub-ledger read 38,519 but the GL truth was 2,927. Receivable
  2041.         // (client) heads are debit-nature (dr−cr); payable (supplier) heads credit-nature (cr−dr).
  2042.         // NULLIF(rate,0)→1 keeps base-currency legs (no rate) unconverted.
  2043.         $rawScalar = function ($sql) use ($em) {
  2044.             try { $v $em->getConnection()->fetchOne($sql); return ($v === null || $v === false) ? 0.0 : (float) $v; }
  2045.             catch (\Throwable $e) { return 0.0; }
  2046.         };
  2047.         $arOutstanding $rawScalar(
  2048.             "SELECT COALESCE(SUM(td.amount * COALESCE(NULLIF(td.currency_multiply_rate,0),1) * (CASE WHEN td.position='dr' THEN 1 ELSE -1 END)),0)
  2049.                FROM acc_transaction_details td
  2050.               WHERE td.accounts_head_id IN (SELECT accounts_head_id FROM acc_clients WHERE accounts_head_id IS NOT NULL)");
  2051.         $apOutstanding $rawScalar(
  2052.             "SELECT COALESCE(SUM(td.amount * COALESCE(NULLIF(td.currency_multiply_rate,0),1) * (CASE WHEN td.position='cr' THEN 1 ELSE -1 END)),0)
  2053.                FROM acc_transaction_details td
  2054.               WHERE td.accounts_head_id IN (SELECT accounts_head_id FROM acc_suppliers WHERE accounts_head_id IS NOT NULL)");
  2055.         $monthStart = (new \DateTime('first day of this month 00:00:00'))->format('Y-m-d H:i:s');
  2056.         $salesThisMonth   = (float) $scalar("SELECT COALESCE(SUM(i.invoiceAmount),0) FROM ApplicationBundle:SalesInvoice i WHERE i.createdAt >= :d AND (i.deleteFlag = 0 OR i.deleteFlag IS NULL)", ['d' => $monthStart]);
  2057.         $expenseThisMonth = (float) $scalar("SELECT COALESCE(SUM(e.invoiceAmount),0) FROM ApplicationBundle:ExpenseInvoice e WHERE e.createdAt >= :d AND (e.deleteFlag = 0 OR e.deleteFlag IS NULL)", ['d' => $monthStart]);
  2058.         // â”€â”€ Reuse the company cash-flow builder for the mini trend + current cash â”€â”€
  2059.         $cashFlow = ['hasData' => false];
  2060.         try { $cashFlow $this->buildCompanyCashFlow($em12); } catch (\Throwable $e) { $cashFlow = ['hasData' => false]; }
  2061.         // Base (functional) currency so the money tiles are labelled, not bare numbers.
  2062.         $baseCurrency '';
  2063.         try { $baseCurrency = (string) \ApplicationBundle\Modules\Accounts\Service\CompanyCurrencyResolver::getFunctionalCurrencyCode($em1); } catch (\Throwable $e) { $baseCurrency ''; }
  2064.         // â”€â”€ Per-bank balances (owner request: "see individual balance of banks") â”€â”€
  2065.         // Deliberately computed with the SAME expression buildCompanyCashFlow uses for
  2066.         // the Current Cash tile â€” posted rows only (ledger_hit = 1), dr positive, and
  2067.         // amount * currency_multiply_rate so foreign accounts land in base currency.
  2068.         // Anything else and the rows here would quietly disagree with the tile above them.
  2069.         // Cash & bank is wider than bank_accounts (cash-in-hand heads carry no bank row),
  2070.         // so the leftover is surfaced as its own line rather than silently dropped â€”
  2071.         // the listed banks plus that remainder equal Current Cash exactly.
  2072.         $bankBalances = [];
  2073.         $bankOther    0.0;
  2074.         try {
  2075.             $conn2    $em->getConnection();
  2076.             $baseExpr "td.amount * COALESCE(NULLIF(td.currency_multiply_rate, ''), 1)";
  2077.             $drCond   "LOWER(TRIM(td.position)) = 'dr'";
  2078.             // Driven off the GL, NOT off bank_accounts. bank_accounts.accounts_head_id is
  2079.             // not dependable: on the dev tenant all seven rows point at ROOT heads
  2080.             // (Assets, Revenue, Expense...) which carry no postings, so a bank_accounts-
  2081.             // driven card renders seven lines of 0.00 labelled "Revenue". Grouping the
  2082.             // _CACEP_ subtree by head instead gives the real accounts ("Brac Bank Limited
  2083.             // A/C#155120494", "Cash in Hand (Head Office)") AND reconciles to Current Cash
  2084.             // by construction, because it is the same head set and the same expression.
  2085.             // bank_accounts is then used only to ENRICH a row (account no. / currency)
  2086.             // where its head happens to match â€” never to decide which rows exist.
  2087.             $marked $conn2->fetchAllAssociative(
  2088.                 "SELECT accounts_head_id, path_tree FROM acc_accounts_head WHERE marker_hash LIKE '%_CACEP_%'");
  2089.             $ids = [];
  2090.             $likeParts = [];
  2091.             $params = [];
  2092.             foreach ($marked as $m) {
  2093.                 $hid = (int) $m['accounts_head_id'];
  2094.                 $ids[$hid] = $hid;
  2095.                 $likeParts[] = 'path_tree LIKE ?';
  2096.                 $params[]    = ((string) $m['path_tree']) . $hid '/%';
  2097.             }
  2098.             if ($likeParts) {
  2099.                 foreach ($conn2->fetchAllAssociative(
  2100.                     'SELECT accounts_head_id FROM acc_accounts_head WHERE ' implode(' OR '$likeParts), $params) as $d) {
  2101.                     $ids[(int) $d['accounts_head_id']] = (int) $d['accounts_head_id'];
  2102.                 }
  2103.             }
  2104.             // max_rate below flags whether any posting on the head was booked at a non-1
  2105.             // FX rate. Every balance is BASE currency (amount x rate); a head can carry
  2106.             // postings in several currencies at once (head 1721 on dev mixes rate 1 and
  2107.             // rate 117.09), so a native-currency sum would add two different units and
  2108.             // mean nothing. The card labels the unit once and marks converted heads FX.
  2109.             $rows = [];
  2110.             if ($ids) {
  2111.                 $inClause implode(','array_map('intval'$ids));
  2112.                 $rows $conn2->fetchAllAssociative(
  2113.                     "SELECT h.accounts_head_id AS hid,
  2114.                             h.name AS bank_name,
  2115.                             MAX(ba.account_number) AS account_number,
  2116.                             MAX(ba.branch_name)    AS branch_name,
  2117.                             MAX(ba.currency_code)  AS currency_code,
  2118.                             MAX(COALESCE(NULLIF(td.currency_multiply_rate, ''), 1)) AS max_rate,
  2119.                             SUM(CASE WHEN $drCond THEN $baseExpr ELSE -($baseExpr) END) AS balance
  2120.                        FROM acc_transaction_details td
  2121.                        JOIN acc_transactions t ON t.transaction_id = td.transaction_id
  2122.                        JOIN acc_accounts_head h ON h.accounts_head_id = td.accounts_head_id
  2123.                   LEFT JOIN bank_accounts ba ON ba.accounts_head_id = h.accounts_head_id
  2124.                       WHERE td.accounts_head_id IN ($inClause) AND td.ledger_hit = 1
  2125.                    GROUP BY h.accounts_head_id, h.name
  2126.                      HAVING ROUND(balance, 2) <> 0
  2127.                    ORDER BY balance DESC");
  2128.             }
  2129.             foreach ($rows as $r) {
  2130.                 $bankBalances[] = [
  2131.                     'head_id'  => (int) $r['hid'],
  2132.                     'name'     => (string) $r['bank_name'],
  2133.                     'account'  => trim((string) $r['account_number']),
  2134.                     'branch'   => trim((string) $r['branch_name']),
  2135.                     'currency' => trim((string) $r['currency_code']),
  2136.                     // true when at least one posting was booked at a non-1 FX rate, i.e.
  2137.                     // this figure includes converted foreign-currency movement.
  2138.                     'has_fx'   => ((float) $r['max_rate']) != 1.0,
  2139.                     'balance'  => round((float) $r['balance'], 2),
  2140.                 ];
  2141.             }
  2142.             if (isset($cashFlow['closingBalance'])) {
  2143.                 $listed    array_sum(array_column($bankBalances'balance'));
  2144.                 $bankOther round(((float) $cashFlow['closingBalance']) - $listed2);
  2145.             }
  2146.         } catch (\Throwable $e) {
  2147.             // Fail soft so the dashboard still renders â€” but LOG it. The first version of
  2148.             // this block had three wrong identifiers and the silent catch turned all of
  2149.             // them into "card just doesn't appear", which is indistinguishable from a
  2150.             // tenant that has no bank accounts. Silence is not an acceptable failure mode.
  2151.             $bankBalances = [];
  2152.             $bankOther    0.0;
  2153.             try { $this->get('logger')->error('finance dashboard: bank balances query failed: ' $e->getMessage()); } catch (\Throwable $ignored) {}
  2154.         }
  2155.         // Totals computed HERE, not in the template: a {% set %} inside a Twig {% for %}
  2156.         // is scoped to the loop, so accumulating across rows in the view silently yields
  2157.         // the initial value. Bar widths need the max, the footer needs the sum.
  2158.         $bankSum round(array_sum(array_column($bankBalances'balance')), 2);
  2159.         $bankMax 1.0;
  2160.         foreach ($bankBalances as $b) { $bankMax max($bankMaxabs($b['balance'])); }
  2161.         return [
  2162.             'base_currency' => $baseCurrency,
  2163.             // route + hint make each figure click-through to its rows. The hint states
  2164.             // what the number actually counts, because these lists take no filter
  2165.             // parameters â€” a card that is a SUBSET of its destination says so rather
  2166.             // than implying a filter that is not applied.
  2167.             'kpis' => [
  2168.                 ['label' => 'Sales Invoices',   'value' => $salesInv,   'note' => 'Receivables',
  2169.                  'route' => 'sales_invoices',   'hint' => 'All non-deleted sales invoices. Opens the Sales Invoice list.'],
  2170.                 ['label' => 'Expense Invoices''value' => $expenseInv'note' => 'Payables',
  2171.                  'route' => 'expense_invoices''hint' => 'All non-deleted expense invoices. Opens the Expense Invoice list.'],
  2172.                 ['label' => 'Bank Accounts',    'value' => $banks,      'note' => 'Cash & bank',
  2173.                  'route' => 'bank_account_list','hint' => 'Every bank account record. Opens the Bank Account list.'],
  2174.                 ['label' => 'Pending AR',       'value' => $salesPending'note' => 'Sales invoices to approve',
  2175.                  'route' => 'pending_invoices''hint' => 'Sales invoices not yet approved. Opens the Pending Invoice list.'],
  2176.                 ['label' => 'Pending AP',       'value' => $expPending,   'note' => 'Expense invoices to approve',
  2177.                  'route' => 'expense_invoice_approval_queue''hint' => 'Expense invoices not yet approved. Opens the Expense Approval Queue.'],
  2178.             ],
  2179.             'money' => [
  2180.                 ['label' => 'Current Cash',       'value' => isset($cashFlow['closingBalance']) ? $cashFlow['closingBalance'] : 0'note' => 'Cash & bank balance',   'accent' => 'a',
  2181.                  'route' => 'bank_account_list''hint' => 'Closing cash & bank balance. Opens the Bank Account list.'],
  2182.                 // These two tiles are LEDGER balances: net movement on the customer /
  2183.                 // supplier control heads in acc_transaction_details, all-time. The ageing
  2184.                 // reports they open age OPEN INVOICE dues instead. Those are different
  2185.                 // quantities and only coincide in a fully reconciled book, so the hint
  2186.                 // says so rather than implying the report is a breakdown of the tile.
  2187.                 ['label' => 'Receivable Due',     'value' => round($arOutstanding2),  'note' => 'Outstanding from customers''accent' => 'b',
  2188.                  'route' => 'ageing_receivable''hint' => 'Ledger balance: net debit on customer control heads. Opens Receivable Ageing, which ages open invoice dues â€” a different basis, so the totals need not match.'],
  2189.                 ['label' => 'Payable Due',        'value' => round($apOutstanding2),  'note' => 'Outstanding to suppliers',   'accent' => 'c',
  2190.                  'route' => 'ageing_payable',    'hint' => 'Ledger balance: net credit on supplier control heads. Opens Payable Ageing, which ages open invoice dues â€” a different basis, so the totals need not match.'],
  2191.                 ['label' => 'Invoiced (mo)',      'value' => round($salesThisMonth2), 'note' => 'Sales billed this month',     'accent' => 'b',
  2192.                  'route' => 'sales_invoices',    'hint' => 'Sales invoiced since the 1st of this month. Opens the full Sales Invoice list.'],
  2193.                 ['label' => 'Expensed (mo)',      'value' => round($expenseThisMonth2), 'note' => 'Expenses this month',       'accent' => 'c',
  2194.                  'route' => 'expense_invoices',  'hint' => 'Expenses booked since the 1st of this month. Opens the full Expense Invoice list.'],
  2195.             ],
  2196.             'cashFlow' => $cashFlow,
  2197.             // One card, one row per bank â€” NOT a tile each. See finance_dashboard.html.twig.
  2198.             'bank_balances' => $bankBalances,
  2199.             'bank_other'    => $bankOther,
  2200.             'bank_sum'      => $bankSum,
  2201.             'bank_max'      => $bankMax,
  2202.             'pending_items' => [
  2203.                 ['label' => 'Sales Invoices',   'value' => $salesPending'note' => 'Receivable approvals'],
  2204.                 ['label' => 'Expense Invoices''value' => $expPending,   'note' => 'Payable approvals'],
  2205.             ],
  2206.         ];
  2207.     }
  2208.     public function indexSalesAction(Request $request)
  2209.     {
  2210.         $session $request->getSession();
  2211.         $dashboardDataForUser = [];
  2212.         $em $this->getDoctrine()->getManager();
  2213.         $companyId $this->getLoggedUserCompanyId($request);
  2214.         $userId $request->getSession()->get(UserConstants::USER_ID);
  2215.         $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  2216.             array(
  2217.                 'CompanyId' => $companyId,
  2218.                 'userId' => $userId,
  2219.                 'status' => GeneralConstant::ACTIVE
  2220.             ),
  2221.             array(
  2222.                 'sequence' => 'ASC'
  2223.             )
  2224.         );
  2225.         if (empty($dbQuery))   ///now get the defaults
  2226.             $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  2227.                 array(
  2228.                     'CompanyId' => $companyId,
  2229.                     //                    'userId'=>$userId,
  2230.                     'defaultBoxFlag' => 1,
  2231.                     'status' => GeneralConstant::ACTIVE
  2232.                 ),
  2233.                 array(
  2234.                     'sequence' => 'ASC'
  2235.                 )
  2236.             );
  2237.         foreach ($dbQuery as $entry) {
  2238.             $dashboardDataForUser[] = array(
  2239.                 'id' => $entry->getId(),
  2240.                 'widgetId' => $entry->getId(),
  2241.                 'widgetSequence' => $entry->getSequence(),
  2242.                 'widgetStatus' => $entry->getStatus(),
  2243.                 'widgetData' => json_decode($entry->getData(), true),
  2244.                 'defaultBoxFlag' => $entry->getDefaultBoxFlag(),
  2245.                 'widgetSizeTiny' => $entry->getSizeTiny(),
  2246.                 'widgetSizeSmall' => $entry->getSizeSmall(),
  2247.                 'widgetSizeMedium' => $entry->getSizeMedium(),
  2248.                 'widgetSizeLarge' => $entry->getSizeLarge(),
  2249.                 'refreshInterval' => $entry->getRefreshInterval(),
  2250.             );
  2251.         }
  2252.         if ($session->has('isMobile')) {
  2253.             if ($session->get('isMobile') == true) {
  2254.                 return $this->render(
  2255.                     '@Application/pages/dashboard/index_finance_mobile.html.twig',
  2256.                     array(
  2257.                         'page_title' => 'Finance Dashboard',
  2258.                         'dashboardDataForUser' => $dashboardDataForUser
  2259.                     )
  2260.                 );
  2261.             } else {
  2262.             }
  2263.         }
  2264.         return $this->render(
  2265.             '@Sales/pages/sales_dashboard.html.twig',
  2266.             array(
  2267.                 'page_title' => 'Sales Dashboard',
  2268.                 'dashboardDataForUser' => $dashboardDataForUser,
  2269.                 'dashboardAnalytics' => $this->buildSalesDashboardAnalytics($em)
  2270.             )
  2271.         );
  2272.     }
  2273.     /**
  2274.      * Fail-safe analytics for the Sales cp-shell dashboard â€” KPIs + 6-month order-value trend +
  2275.      * a health snapshot. Every metric/query is guarded so a schema/tenant quirk degrades to
  2276.      * empty rather than 500-ing the dashboard.
  2277.      */
  2278.     private function buildSalesDashboardAnalytics($em)
  2279.     {
  2280.         $scalar = function ($dql$params = []) use ($em) {
  2281.             try {
  2282.                 $v $em->createQuery($dql)->setParameters($params)->getSingleScalarResult();
  2283.                 return $v === null $v;
  2284.             } catch (\Throwable $e) {
  2285.                 return 0;
  2286.             }
  2287.         };
  2288.         // â”€â”€ SW â€” the business-line lens on the DOCUMENT-DERIVED figures â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
  2289.         // BOUNDARY (owner-stated, enforced here): counts and values computed FROM sales
  2290.         // documents wear the lens; anything sourced from the LEDGER or the party master does
  2291.         // NOT â€” the customer count below stays company-wide, because a workspace may filter
  2292.         // activity but never re-total what it does not own (plan law #1). Fails OPEN.
  2293.         $wsAllowedDash null;
  2294.         try {
  2295.             $wsSvcDash = new \ApplicationBundle\Modules\SalesWorkspace\Service\WorkspaceAdminService($em);
  2296.             $wsUidDash = (int) $request->getSession()->get(UserConstants::USER_ID0);
  2297.             $wsAllowedDash $wsSvcDash->allowedIdsFor($wsUidDash$wsSvcDash->isAdminUser($wsUidDash));
  2298.         } catch (\Throwable $eWs) { $wsAllowedDash null; }
  2299.         $wsDqlAnd = function ($alias) use ($wsAllowedDash) {
  2300.             $c = \ApplicationBundle\Modules\SalesWorkspace\Support\WorkspaceScope::dqlPredicate($alias$wsAllowedDash);
  2301.             return $c === '' '' ' AND ' $c;
  2302.         };
  2303.         $wsSqlAnd = function ($alias) use ($wsAllowedDash) {
  2304.             if ($wsAllowedDash === null) { return ''; }
  2305.             return ' AND ' . \ApplicationBundle\Modules\SalesWorkspace\Support\WorkspaceScope::sqlPredicate($alias$wsAllowedDash);
  2306.         };
  2307.         $wsScoped $wsAllowedDash !== null;   // the view says so when it is filtered
  2308.         $soTotal    = (int) $scalar("SELECT COUNT(s) FROM ApplicationBundle:SalesOrder s WHERE (s.deleteFlag = 0 OR s.deleteFlag IS NULL)" $wsDqlAnd('s'));
  2309.         $soApproved = (int) $scalar("SELECT COUNT(s) FROM ApplicationBundle:SalesOrder s WHERE s.approved = :a AND (s.deleteFlag = 0 OR s.deleteFlag IS NULL)" $wsDqlAnd('s'), ['a' => GeneralConstant::APPROVED]);
  2310.         $soValue    = (float) $scalar("SELECT SUM(s.soAmount) FROM ApplicationBundle:SalesOrder s WHERE s.approved = :a AND (s.deleteFlag = 0 OR s.deleteFlag IS NULL)" $wsDqlAnd('s'), ['a' => GeneralConstant::APPROVED]);
  2311.         $soPending  max($soTotal $soApproved0);
  2312.         $opps       = (int) $scalar("SELECT COUNT(o) FROM ApplicationBundle:Opportunity o WHERE (o.deleteFlag = 0 OR o.deleteFlag IS NULL)");
  2313.         $clients    = (int) $scalar("SELECT COUNT(c) FROM ApplicationBundle:AccClients c");
  2314.         // â”€â”€ 6-month order-value trend (guarded raw SQL â€” flat/empty on any quirk) â”€â”€
  2315.         $monthKeys = [];
  2316.         $monthLabels = [];
  2317.         for ($i 5$i >= 0$i--) {
  2318.             $m = new \DateTime('first day of this month');
  2319.             if ($i 0) {
  2320.                 $m->modify('-' $i ' month');
  2321.             }
  2322.             $monthKeys[] = $m->format('Y-m');
  2323.             $monthLabels[] = $m->format('M');
  2324.         }
  2325.         $trend = function ($sql) use ($em) {
  2326.             try {
  2327.                 return $em->getConnection()->fetchAllAssociative($sql);
  2328.             } catch (\Throwable $e) {
  2329.                 return [];
  2330.             }
  2331.         };
  2332.         $seriesFromRows = function (array $rows, array $keys) {
  2333.             $map = [];
  2334.             foreach ($rows as $r) {
  2335.                 $map[$r['month']] = (float) $r['total'];
  2336.             }
  2337.             $out = [];
  2338.             foreach ($keys as $k) {
  2339.                 $out[] = isset($map[$k]) ? round($map[$k], 2) : 0;
  2340.             }
  2341.             return $out;
  2342.         };
  2343.         $orderRows $trend("
  2344.             SELECT DATE_FORMAT(sales_order_date, '%Y-%m') AS month,
  2345.                    COALESCE(SUM(CAST(COALESCE(NULLIF(so_amount,''),0) AS DECIMAL(15,2))),0) AS total
  2346.             FROM sales_order
  2347.             WHERE status = 1 AND (delete_flag = 0 OR delete_flag IS NULL)
  2348.               AND sales_order_date >= DATE_SUB(CURDATE(), INTERVAL 5 MONTH)" $wsSqlAnd('sales_order') . "
  2349.             GROUP BY DATE_FORMAT(sales_order_date, '%Y-%m') ORDER BY month ASC");
  2350.         $approvedRows $trend("
  2351.             SELECT DATE_FORMAT(sales_order_date, '%Y-%m') AS month,
  2352.                    COALESCE(SUM(CAST(COALESCE(NULLIF(so_amount,''),0) AS DECIMAL(15,2))),0) AS total
  2353.             FROM sales_order
  2354.             WHERE status = 1 AND approved = 1 AND (delete_flag = 0 OR delete_flag IS NULL)
  2355.               AND sales_order_date >= DATE_SUB(CURDATE(), INTERVAL 5 MONTH)" $wsSqlAnd('sales_order') . "
  2356.             GROUP BY DATE_FORMAT(sales_order_date, '%Y-%m') ORDER BY month ASC");
  2357.         $coverage $soTotal round(($soApproved $soTotal) * 1001) : 0;
  2358.         // â”€â”€ Intelligent helper â€” surface the most useful next action â”€â”€
  2359.         if ($soPending 0) {
  2360.             $salesHelper = ['type' => 'warn''text' => $soPending ' sales order' . ($soPending == '' 's') . ' awaiting approval â€” sign off to release delivery.'];
  2361.         } elseif ($opps 0) {
  2362.             $salesHelper = ['type' => 'ok''text' => $opps ' opportunit' . ($opps == 'y' 'ies') . ' in the pipeline and nothing stuck in approval â€” keep them moving.'];
  2363.         } else {
  2364.             $salesHelper null;
  2365.         }
  2366.         return [
  2367.             // SW: the view must SAY when these figures are a line's, not the company's.
  2368.             'scoped' => $wsScoped,
  2369.             'helper' => $salesHelper,
  2370.             // `route` makes each KPI click-through to the rows behind it; `hint` states
  2371.             // the figure's actual definition on hover. The lists these open take no
  2372.             // filter parameters, so a card whose figure is a SUBSET of its destination
  2373.             // says so in the hint rather than pretending the destination is filtered â€”
  2374.             // e.g. Approved Value sums only approved orders but opens the full SO list.
  2375.             'kpis' => [
  2376.                 ['label' => 'Sales Orders',     'value' => $soTotal,        'note' => 'Active orders',
  2377.                  'route' => 'sales_orders',        'hint' => 'All sales orders that are not deleted. Opens the Sales Order list.'],
  2378.                 ['label' => 'Approved Value',   'value' => round($soValue), 'note' => 'Approved SO value',
  2379.                  'route' => 'sales_orders',        'hint' => 'Sum of so_amount over APPROVED sales orders. Opens the full Sales Order list.'],
  2380.                 ['label' => 'Opportunities',    'value' => $opps,           'note' => 'In the pipeline',
  2381.                  'route' => 'opportunity_list',    'hint' => 'All opportunities that are not deleted. Opens the Opportunity list.'],
  2382.                 ['label' => 'Clients',          'value' => $clients,        'note' => 'Customer base',
  2383.                  'route' => 'client_list',         'hint' => 'Every client record. Opens the Client list.'],
  2384.                 ['label' => 'Pending Approval''value' => $soPending,      'note' => 'Awaiting sign-off',
  2385.                  'route' => 'client_pending_sales_orders''hint' => 'Sales orders not yet approved (total minus approved). Opens Pending Sales Orders.'],
  2386.             ],
  2387.             'pending_items' => [
  2388.                 ['label' => 'Sales Orders''value' => $soPending'note' => 'Waiting for approval'],
  2389.             ],
  2390.             'hero' => [
  2391.                 'labels' => $monthLabels,
  2392.                 'series' => [
  2393.                     ['label' => 'Order Value''values' => $seriesFromRows($orderRows$monthKeys),    'color' => '#2b5fb8''fill' => 'rgba(43,95,184,0.14)'],
  2394.                     ['label' => 'Approved',    'values' => $seriesFromRows($approvedRows$monthKeys), 'color' => '#4BAA6B''fill' => 'rgba(75,170,107,0.14)'],
  2395.                 ],
  2396.             ],
  2397.             'hero_summary' => [
  2398.                 'subhead' => 'Order value over the last 6 months',
  2399.             ],
  2400.             'snapshot' => [
  2401.                 'label' => 'Sales Health',
  2402.                 'ring_value' => $coverage,
  2403.                 'ring_note' => 'Approved of all orders',
  2404.                 'metrics' => [
  2405.                     ['label' => 'Approved Value''value' => number_format(round($soValue)), 'note' => 'Signed-off SO value'],
  2406.                     ['label' => 'Pending Orders''value' => $soPending'note' => 'Awaiting approval'],
  2407.                     ['label' => 'Opportunities',  'value' => $opps,      'note' => 'Open pipeline'],
  2408.                 ],
  2409.             ],
  2410.         ];
  2411.     }
  2412.     public function indexPurchaseAction(Request $request)
  2413.     {
  2414.         $em $this->getDoctrine()->getManager();
  2415.         $companyId $this->getLoggedUserCompanyId($request);
  2416.         $dashboardDataForUser $this->loadDashboardWidgetsForUser($request);
  2417.         $dashboardAnalytics $this->buildPurchaseDashboardAnalytics($em$companyId);
  2418.         return $this->render(
  2419.             '@Purchase/pages/supply_chain_dashboard.html.twig',
  2420.             array(
  2421.                 'page_title' => 'Purchasing Dashboard',
  2422.                 'dashboardMode' => 'purchase',
  2423.                 'dashboardDataForUser' => $dashboardDataForUser,
  2424.                 'dashboardAnalytics' => $dashboardAnalytics
  2425.             )
  2426.         );
  2427.     }
  2428.     public function indexDistributionAction(Request $request)
  2429.     {
  2430.         $session $request->getSession();
  2431.         $dashboardDataForUser = [];
  2432.         $em $this->getDoctrine()->getManager();
  2433.         $companyId $this->getLoggedUserCompanyId($request);
  2434.         $userId $request->getSession()->get(UserConstants::USER_ID);
  2435.         $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  2436.             array(
  2437.                 'CompanyId' => $companyId,
  2438.                 'userId' => $userId,
  2439.                 'status' => GeneralConstant::ACTIVE
  2440.             ),
  2441.             array(
  2442.                 'sequence' => 'ASC'
  2443.             )
  2444.         );
  2445.         if (empty($dbQuery))   ///now get the defaults
  2446.             $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  2447.                 array(
  2448.                     'CompanyId' => $companyId,
  2449.                     //                    'userId'=>$userId,
  2450.                     'defaultBoxFlag' => 1,
  2451.                     'status' => GeneralConstant::ACTIVE
  2452.                 ),
  2453.                 array(
  2454.                     'sequence' => 'ASC'
  2455.                 )
  2456.             );
  2457.         foreach ($dbQuery as $entry) {
  2458.             $dashboardDataForUser[] = array(
  2459.                 'id' => $entry->getId(),
  2460.                 'widgetId' => $entry->getId(),
  2461.                 'widgetSequence' => $entry->getSequence(),
  2462.                 'widgetStatus' => $entry->getStatus(),
  2463.                 'widgetData' => json_decode($entry->getData(), true),
  2464.                 'defaultBoxFlag' => $entry->getDefaultBoxFlag(),
  2465.                 'widgetSizeTiny' => $entry->getSizeTiny(),
  2466.                 'widgetSizeSmall' => $entry->getSizeSmall(),
  2467.                 'widgetSizeMedium' => $entry->getSizeMedium(),
  2468.                 'widgetSizeLarge' => $entry->getSizeLarge(),
  2469.                 'refreshInterval' => $entry->getRefreshInterval(),
  2470.             );
  2471.         }
  2472.         return $this->render(
  2473.             '@Distribution/pages/distribution_dashboard.html.twig',
  2474.             array(
  2475.                 'page_title' => 'Distribution Dashboard',
  2476.                 'dashboardDataForUser' => $dashboardDataForUser,
  2477.                 'dashboardAnalytics' => $this->buildDistributionDashboardAnalytics($em)
  2478.             )
  2479.         );
  2480.     }
  2481.     /**
  2482.      * Lean, fail-safe analytics for the Distribution cp-shell dashboard. Guarded scalar DQL â€”
  2483.      * a schema/tenant quirk degrades to 0 rather than 500-ing the dashboard.
  2484.      */
  2485.     private function buildDistributionDashboardAnalytics($em)
  2486.     {
  2487.         $scalar = function ($dql$params = []) use ($em) {
  2488.             try {
  2489.                 $v $em->createQuery($dql)->setParameters($params)->getSingleScalarResult();
  2490.                 return $v === null $v;
  2491.             } catch (\Throwable $e) {
  2492.                 return 0;
  2493.             }
  2494.         };
  2495.         $doTotal    = (int) $scalar("SELECT COUNT(d) FROM ApplicationBundle:DeliveryOrder d WHERE (d.deleteFlag = 0 OR d.deleteFlag IS NULL)");
  2496.         $doApproved = (int) $scalar("SELECT COUNT(d) FROM ApplicationBundle:DeliveryOrder d WHERE d.approved = :a AND (d.deleteFlag = 0 OR d.deleteFlag IS NULL)", ['a' => GeneralConstant::APPROVED]);
  2497.         $doPending  max($doTotal $doApproved0);
  2498.         $confirms   = (int) $scalar("SELECT COUNT(c) FROM ApplicationBundle:DeliveryConfirmation c");
  2499.         $receipts   = (int) $scalar("SELECT COUNT(r) FROM ApplicationBundle:DeliveryReceipt r");
  2500.         $challans   = (int) $scalar("SELECT COUNT(s) FROM ApplicationBundle:ServiceChallan s");
  2501.         return [
  2502.             'kpis' => [
  2503.                 ['label' => 'Delivery Orders',   'value' => $doTotal,   'note' => 'All dispatch orders'],
  2504.                 ['label' => 'Confirmations',     'value' => $confirms,  'note' => 'Delivery confirmed'],
  2505.                 ['label' => 'Delivery Receipts''value' => $receipts,  'note' => 'Received by customer'],
  2506.                 ['label' => 'Service Challans',  'value' => $challans,  'note' => 'Dispatch challans'],
  2507.                 ['label' => 'Pending Dispatch',  'value' => $doPending'note' => 'Awaiting sign-off'],
  2508.             ],
  2509.             'pending_items' => [
  2510.                 ['label' => 'Delivery Orders''value' => $doPending'note' => 'Waiting for approval'],
  2511.             ],
  2512.         ];
  2513.     }
  2514.     public function indexProjectsAction(Request $request)
  2515.     {
  2516.         $em $this->getDoctrine()->getManager();
  2517.         return $this->render(
  2518.             '@Project/pages/projects_dashboard.html.twig',
  2519.             array(
  2520.                 'page_title' => 'Projects Dashboard',
  2521.                 'dashboardAnalytics' => $this->buildProjectsDashboardAnalytics($em),
  2522.             )
  2523.         );
  2524.     }
  2525.     /**
  2526.      * Lean, fail-safe analytics for the Projects cp-shell home. Guarded scalar DQL â€” a
  2527.      * schema/tenant quirk degrades each metric to 0 rather than 500-ing the landing page.
  2528.      * Project.deleteFlag is nullable-with-no-default, so every count uses (=0 OR IS NULL).
  2529.      */
  2530.     private function buildProjectsDashboardAnalytics($em)
  2531.     {
  2532.         $scalar = function ($dql$params = []) use ($em) {
  2533.             try {
  2534.                 $v $em->createQuery($dql)->setParameters($params)->getSingleScalarResult();
  2535.                 return $v === null $v;
  2536.             } catch (\Throwable $e) {
  2537.                 return 0;
  2538.             }
  2539.         };
  2540.         $list = function ($dql$params = [], $max 6) use ($em) {
  2541.             try {
  2542.                 $q $em->createQuery($dql)->setParameters($params)->setMaxResults($max);
  2543.                 return $q->getArrayResult();
  2544.             } catch (\Throwable $e) { return []; }
  2545.         };
  2546.         $today date('Y-m-d');
  2547.         $total     = (int) $scalar("SELECT COUNT(p) FROM ApplicationBundle:Project p WHERE (p.deleteFlag = 0 OR p.deleteFlag IS NULL)");
  2548.         $active    = (int) $scalar("SELECT COUNT(p) FROM ApplicationBundle:Project p WHERE p.status = :s AND (p.deleteFlag = 0 OR p.deleteFlag IS NULL)", ['s' => GeneralConstant::ACTIVE]);
  2549.         $baselines = (int) $scalar("SELECT COUNT(b) FROM ApplicationBundle:ProjectConfigBaseline b");
  2550.         // â”€â”€ Project confirmation status mix (0/null budgeting, 2 confirmed-not-impacted, 1 impacted) â”€â”€
  2551.         $budgeting = (int) $scalar("SELECT COUNT(p) FROM ApplicationBundle:Project p WHERE (p.projectConfirmationStatus = 0 OR p.projectConfirmationStatus IS NULL) AND (p.deleteFlag = 0 OR p.deleteFlag IS NULL)");
  2552.         $confirmed = (int) $scalar("SELECT COUNT(p) FROM ApplicationBundle:Project p WHERE p.projectConfirmationStatus = 2 AND (p.deleteFlag = 0 OR p.deleteFlag IS NULL)");
  2553.         $impacted  = (int) $scalar("SELECT COUNT(p) FROM ApplicationBundle:Project p WHERE p.projectConfirmationStatus = 1 AND (p.deleteFlag = 0 OR p.deleteFlag IS NULL)");
  2554.         // â”€â”€ Milestone health â”€â”€
  2555.         $msTotal     = (int) $scalar("SELECT COUNT(m) FROM ApplicationBundle:ProjectMilestone m");
  2556.         $msDone       = (int) $scalar("SELECT COUNT(m) FROM ApplicationBundle:ProjectMilestone m WHERE m.actualDate IS NOT NULL");
  2557.         $msOverdue   = (int) $scalar("SELECT COUNT(m) FROM ApplicationBundle:ProjectMilestone m WHERE m.actualDate IS NULL AND m.plannedDate IS NOT NULL AND m.plannedDate < :t", ['t' => $today]);
  2558.         $msUpcoming  = (int) $scalar("SELECT COUNT(m) FROM ApplicationBundle:ProjectMilestone m WHERE m.actualDate IS NULL AND m.plannedDate >= :t", ['t' => $today]);
  2559.         $msBilling   = (float) $scalar("SELECT COALESCE(SUM(m.billingAmount),0) FROM ApplicationBundle:ProjectMilestone m");
  2560.         $msInvoiced  = (float) $scalar("SELECT COALESCE(SUM(m.billingAmount),0) FROM ApplicationBundle:ProjectMilestone m WHERE m.invoicedDate IS NOT NULL");
  2561.         $pctComplete $msTotal round($msDone $msTotal 100) : 0;
  2562.         // â”€â”€ Upcoming milestones (not yet done, soonest first) â”€â”€
  2563.         $upRows $list("SELECT m.milestoneName AS name, m.plannedDate AS planned, m.billingAmount AS amount
  2564.                             FROM ApplicationBundle:ProjectMilestone m
  2565.                            WHERE m.actualDate IS NULL AND m.plannedDate >= :t
  2566.                            ORDER BY m.plannedDate ASC", ['t' => $today], 5);
  2567.         $upcoming = [];
  2568.         foreach ($upRows as $r) {
  2569.             $upcoming[] = [
  2570.                 'name'    => $r['name'] ?: 'Milestone',
  2571.                 'date'    => $r['planned'] instanceof \DateTimeInterface $r['planned']->format('Y-m-d') : (is_string($r['planned']) ? substr($r['planned'], 010) : ''),
  2572.                 'amount'  => number_format((float) ($r['amount'] ?? 0), 2'.'','),
  2573.             ];
  2574.         }
  2575.         // â”€â”€ CoPilot surface counts â”€â”€
  2576.         $surfaces = [
  2577.             ['label' => 'Requirements',    'value' => (int) $scalar("SELECT COUNT(r) FROM ApplicationBundle:ProjectRequirement r"), 'icon' => 'playlist_add_check',    'route' => 'project_requirement_list'],
  2578.             ['label' => 'Devices',         'value' => (int) $scalar("SELECT COUNT(d) FROM ApplicationBundle:ProjectDevice d"),      'icon' => 'memory',       'route' => 'project_device_list'],
  2579.             ['label' => 'Interfaces',      'value' => (int) $scalar("SELECT COUNT(i) FROM ApplicationBundle:ProjectInterface i"),   'icon' => 'settings_ethernet',        'route' => 'project_interface_list'],
  2580.             ['label' => 'Config Baselines','value' => $baselines,                                                                    'icon' => 'layers',       'route' => 'project_config_baseline_list'],
  2581.         ];
  2582.         // â”€â”€ Sales target vs achievement (current year) â€” fail-safe â”€â”€
  2583.         $tva null;
  2584.         try {
  2585.             $sts = new \ApplicationBundle\Modules\ProjectSalesReport\Service\SalesTargetService($em);
  2586.             $year date('Y');
  2587.             $perf $sts->fprPerformance(\ApplicationBundle\Modules\ProjectSalesReport\Support\SalesTargetCore::YEARLY$year);
  2588.             $tgt = (float) $perf['totals']['target'];
  2589.             $ach = (float) $perf['totals']['achieved'];
  2590.             $tva = [
  2591.                 'period'   => $year,
  2592.                 'target'   => number_format($tgt0'.'','),
  2593.                 'achieved' => number_format($ach0'.'','),
  2594.                 'pct'      => $perf['totals']['achievement_pct'],       // null when no target set
  2595.                 'bar'      => $tgt min(100round($ach $tgt 100)) : 0,
  2596.                 'has_target' => $tgt 0,
  2597.             ];
  2598.         } catch (\Throwable $e) { $tva null; }
  2599.         // â”€â”€ Smart helper â”€â”€
  2600.         if ($msOverdue 0) {
  2601.             $helper = ['type' => 'warn''text' => $msOverdue ' milestone' . ($msOverdue == '' 's') . ' overdue â€” the planned date has passed with no completion recorded. Review delivery on these first.'];
  2602.         } elseif ($msUpcoming 0) {
  2603.             $helper = ['type' => 'ok''text' => $msUpcoming ' milestone' . ($msUpcoming == '' 's') . ' coming up and nothing overdue â€” delivery is on track.'];
  2604.         } else {
  2605.             $helper null;
  2606.         }
  2607.         return [
  2608.             'kpis' => [
  2609.                 ['label' => 'Total Projects''value' => $total,      'note' => 'All non-deleted projects',
  2610.                  'route' => 'project_list''hint' => 'Projects where delete_flag is 0 or unset. Opens the Project list.'],
  2611.                 ['label' => 'Active',          'value' => $active,     'note' => 'Currently active',
  2612.                  'route' => 'project_list''hint' => 'Projects with status = Active. Opens the full Project list.'],
  2613.                 // There is NO global milestone list route â€” milestones are managed inside
  2614.                 // a project â€” so these two anchor to the Milestones card further down this
  2615.                 // same page, which breaks the figures out into overdue/upcoming/done plus
  2616.                 // billing. Better an honest in-page jump than a link to a list that would
  2617.                 // not reconcile, or a dead link.
  2618.                 ['label' => 'Milestones Due',  'value' => $msUpcoming'note' => 'Upcoming, not yet done',
  2619.                  'anchor' => 'pj-milestones''hint' => 'Milestones not done with a planned date from today onward. Jumps to the Milestones card.'],
  2620.                 ['label' => 'Overdue',         'value' => $msOverdue,  'note' => 'Past planned date',
  2621.                  'anchor' => 'pj-milestones''hint' => 'Milestones not done whose planned date has passed. Jumps to the Milestones card.'],
  2622.             ],
  2623.             'status_mix' => [
  2624.                 ['label' => 'Budgeting''value' => $budgeting'color' => '#c98a00'],
  2625.                 ['label' => 'Confirmed''value' => $confirmed'color' => '#1976d2'],
  2626.                 ['label' => 'Impacted',  'value' => $impacted,  'color' => '#2e7d32'],
  2627.             ],
  2628.             'status_total' => $budgeting $confirmed $impacted,
  2629.             'milestones' => [
  2630.                 'total' => $msTotal'done' => $msDone'overdue' => $msOverdue'upcoming' => $msUpcoming,
  2631.                 'pct_complete' => $pctComplete,
  2632.                 'billing_total' => number_format($msBilling2'.'','),
  2633.                 'invoiced_total' => number_format($msInvoiced2'.'','),
  2634.                 'outstanding_total' => number_format(max(0$msBilling $msInvoiced), 2'.'','),
  2635.             ],
  2636.             'surfaces' => $surfaces,
  2637.             'upcoming' => $upcoming,
  2638.             'target_vs_achievement' => $tva,
  2639.             'helper' => $helper,
  2640.             'pending_items' => [
  2641.                 ['label' => 'Open Projects',      'value' => $active,    'note' => 'Active delivery'],
  2642.                 ['label' => 'Overdue Milestones''value' => $msOverdue'note' => 'Past planned date'],
  2643.                 ['label' => 'Due Soon',           'value' => $msUpcoming,'note' => 'Upcoming milestones'],
  2644.             ],
  2645.         ];
  2646.     }
  2647.     public function indexProductionAction(Request $request)
  2648.     {
  2649.         $session $request->getSession();
  2650.         $dashboardDataForUser = [];
  2651.         $em $this->getDoctrine()->getManager();
  2652.         $companyId $this->getLoggedUserCompanyId($request);
  2653.         $userId $request->getSession()->get(UserConstants::USER_ID);
  2654.         $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  2655.             array(
  2656.                 'CompanyId' => $companyId,
  2657.                 'userId' => $userId,
  2658.                 'status' => GeneralConstant::ACTIVE
  2659.             ),
  2660.             array(
  2661.                 'sequence' => 'ASC'
  2662.             )
  2663.         );
  2664.         if (empty($dbQuery))   ///now get the defaults
  2665.             $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  2666.                 array(
  2667.                     'CompanyId' => $companyId,
  2668.                     //                    'userId'=>$userId,
  2669.                     'defaultBoxFlag' => 1,
  2670.                     'status' => GeneralConstant::ACTIVE
  2671.                 ),
  2672.                 array(
  2673.                     'sequence' => 'ASC'
  2674.                 )
  2675.             );
  2676.         foreach ($dbQuery as $entry) {
  2677.             $dashboardDataForUser[] = array(
  2678.                 'id' => $entry->getId(),
  2679.                 'widgetId' => $entry->getId(),
  2680.                 'widgetSequence' => $entry->getSequence(),
  2681.                 'widgetStatus' => $entry->getStatus(),
  2682.                 'widgetData' => json_decode($entry->getData(), true),
  2683.                 'defaultBoxFlag' => $entry->getDefaultBoxFlag(),
  2684.                 'widgetSizeTiny' => $entry->getSizeTiny(),
  2685.                 'widgetSizeSmall' => $entry->getSizeSmall(),
  2686.                 'widgetSizeMedium' => $entry->getSizeMedium(),
  2687.                 'widgetSizeLarge' => $entry->getSizeLarge(),
  2688.                 'refreshInterval' => $entry->getRefreshInterval(),
  2689.             );
  2690.         }
  2691.         return $this->render(
  2692.             '@Production/pages/production_dashboard.html.twig',
  2693.             array(
  2694.                 'page_title' => 'Production Dashboard',
  2695.                 'dashboardDataForUser' => $dashboardDataForUser,
  2696.                 'dashboardAnalytics' => $this->buildProductionDashboardAnalytics($em),
  2697.             )
  2698.         );
  2699.     }
  2700.     /**
  2701.      * Lean, fail-safe analytics for the Production cp-shell dashboard. Guarded scalar DQL â€”
  2702.      * a missing entity/column degrades to 0 rather than 500-ing the page.
  2703.      */
  2704.     private function buildProductionDashboardAnalytics($em)
  2705.     {
  2706.         $scalar = function ($dql) use ($em) {
  2707.             try {
  2708.                 $v $em->createQuery($dql)->getSingleScalarResult();
  2709.                 return $v === null $v;
  2710.             } catch (\Throwable $e) {
  2711.                 return 0;
  2712.             }
  2713.         };
  2714.         $entries   = (int) $scalar("SELECT COUNT(p) FROM ApplicationBundle:Production p");
  2715.         $boms      = (int) $scalar("SELECT COUNT(b) FROM ApplicationBundle:ProductionBom b");
  2716.         $schedules = (int) $scalar("SELECT COUNT(s) FROM ApplicationBundle:ProductionSchedule s");
  2717.         $lines     = (int) $scalar("SELECT COUNT(l) FROM ApplicationBundle:ProductionLine l");
  2718.         return [
  2719.             'kpis' => [
  2720.                 ['label' => 'Production Entries''value' => $entries,   'note' => 'All production runs'],
  2721.                 ['label' => 'Bills of Material',  'value' => $boms,      'note' => 'Defined BOMs'],
  2722.                 ['label' => 'Schedules',          'value' => $schedules'note' => 'Planned runs'],
  2723.                 ['label' => 'Production Lines',   'value' => $lines,     'note' => 'Configured lines'],
  2724.             ],
  2725.             'pending_items' => [],
  2726.         ];
  2727.     }
  2728.     public function indexInventoryAction(Request $request)
  2729.     {
  2730.         $em $this->getDoctrine()->getManager();
  2731.         $companyId $this->getLoggedUserCompanyId($request);
  2732.         $dashboardDataForUser $this->loadDashboardWidgetsForUser($request);
  2733.         $dashboardAnalytics $this->buildInventoryDashboardAnalytics($em$companyId);
  2734.         return $this->render(
  2735.             '@Inventory/pages/inventory_dashboard.html.twig',
  2736.             array(
  2737.                 'page_title' => 'Inventory Dashboard',
  2738.                 'dashboardMode' => 'inventory',
  2739.                 'dashboardDataForUser' => $dashboardDataForUser,
  2740.                 'dashboardAnalytics' => $dashboardAnalytics
  2741.             )
  2742.         );
  2743.     }
  2744.     private function loadDashboardWidgetsForUser(Request $request)
  2745.     {
  2746.         $dashboardDataForUser = [];
  2747.         $em $this->getDoctrine()->getManager();
  2748.         $companyId $this->getLoggedUserCompanyId($request);
  2749.         $userId $request->getSession()->get(UserConstants::USER_ID);
  2750.         $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  2751.             array(
  2752.                 'CompanyId' => $companyId,
  2753.                 'userId' => $userId,
  2754.                 'status' => GeneralConstant::ACTIVE
  2755.             ),
  2756.             array(
  2757.                 'sequence' => 'ASC'
  2758.             )
  2759.         );
  2760.         if (empty($dbQuery)) {
  2761.             $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  2762.                 array(
  2763.                     'CompanyId' => $companyId,
  2764.                     'defaultBoxFlag' => 1,
  2765.                     'status' => GeneralConstant::ACTIVE
  2766.                 ),
  2767.                 array(
  2768.                     'sequence' => 'ASC'
  2769.                 )
  2770.             );
  2771.         }
  2772.         foreach ($dbQuery as $entry) {
  2773.             $dashboardDataForUser[] = array(
  2774.                 'id' => $entry->getId(),
  2775.                 'widgetId' => $entry->getId(),
  2776.                 'widgetSequence' => $entry->getSequence(),
  2777.                 'widgetStatus' => $entry->getStatus(),
  2778.                 'widgetData' => json_decode($entry->getData(), true),
  2779.                 'defaultBoxFlag' => $entry->getDefaultBoxFlag(),
  2780.                 'widgetSizeTiny' => $entry->getSizeTiny(),
  2781.                 'widgetSizeSmall' => $entry->getSizeSmall(),
  2782.                 'widgetSizeMedium' => $entry->getSizeMedium(),
  2783.                 'widgetSizeLarge' => $entry->getSizeLarge(),
  2784.                 'refreshInterval' => $entry->getRefreshInterval(),
  2785.             );
  2786.         }
  2787.         return $dashboardDataForUser;
  2788.     }
  2789.     private function buildPurchaseDashboardAnalytics($em$companyId)
  2790.     {
  2791.         $conn $em->getConnection();
  2792.         $monthKeys = [];
  2793.         $monthLabels = [];
  2794.         for ($i 5$i >= 0$i--) {
  2795.             $month = new \DateTime('first day of this month');
  2796.             if ($i 0) {
  2797.                 $month->modify('-' $i ' month');
  2798.             }
  2799.             $monthKeys[] = $month->format('Y-m');
  2800.             $monthLabels[] = $month->format('M');
  2801.         }
  2802.         $poTrendRows $conn->fetchAllAssociative("
  2803.             SELECT DATE_FORMAT(purchase_order_date, '%Y-%m') AS month, COALESCE(SUM(CAST(COALESCE(NULLIF(po_amount, ''), 0) AS DECIMAL(15,2))), 0) AS total
  2804.             FROM purchase_order
  2805.             WHERE company_id = :companyId
  2806.               AND status = 1
  2807.               AND approved = 1
  2808.               AND purchase_order_date >= DATE_SUB(CURDATE(), INTERVAL 5 MONTH)
  2809.             GROUP BY DATE_FORMAT(purchase_order_date, '%Y-%m')
  2810.             ORDER BY month ASC
  2811.         ", ['companyId' => $companyId]);
  2812.         $invoiceTrendRows $conn->fetchAllAssociative("
  2813.             SELECT DATE_FORMAT(purchase_invoice_date, '%Y-%m') AS month, COALESCE(SUM(CAST(COALESCE(NULLIF(invoice_amount, ''), 0) AS DECIMAL(15,2))), 0) AS total
  2814.             FROM purchase_invoice
  2815.             WHERE company_id = :companyId
  2816.               AND status = 1
  2817.               AND approved = 1
  2818.               AND purchase_invoice_date >= DATE_SUB(CURDATE(), INTERVAL 5 MONTH)
  2819.             GROUP BY DATE_FORMAT(purchase_invoice_date, '%Y-%m')
  2820.             ORDER BY month ASC
  2821.         ", ['companyId' => $companyId]);
  2822.         $paidTrendRows $conn->fetchAllAssociative("
  2823.             SELECT DATE_FORMAT(purchase_invoice_date, '%Y-%m') AS month, COALESCE(SUM(CAST(COALESCE(NULLIF(paid_amount, ''), 0) AS DECIMAL(15,2))), 0) AS total
  2824.             FROM purchase_invoice
  2825.             WHERE company_id = :companyId
  2826.               AND status = 1
  2827.               AND approved = 1
  2828.               AND purchase_invoice_date >= DATE_SUB(CURDATE(), INTERVAL 5 MONTH)
  2829.             GROUP BY DATE_FORMAT(purchase_invoice_date, '%Y-%m')
  2830.             ORDER BY month ASC
  2831.         ", ['companyId' => $companyId]);
  2832.         $requisitionTrendRows $conn->fetchAllAssociative("
  2833.             SELECT DATE_FORMAT(purchase_requisition_date, '%Y-%m') AS month, COUNT(*) AS total
  2834.             FROM purchase_requisition
  2835.             WHERE company_id = :companyId
  2836.               AND status = 1
  2837.               AND purchase_requisition_date >= DATE_SUB(CURDATE(), INTERVAL 5 MONTH)
  2838.             GROUP BY DATE_FORMAT(purchase_requisition_date, '%Y-%m')
  2839.             ORDER BY month ASC
  2840.         ", ['companyId' => $companyId]);
  2841.         $seriesFromRows = function (array $rows, array $monthKeys) {
  2842.             $series array_fill_keys($monthKeys0);
  2843.             foreach ($rows as $row) {
  2844.                 $month $row['month'] ?? null;
  2845.                 if ($month !== null && array_key_exists($month$series)) {
  2846.                     $series[$month] = (float) $row['total'];
  2847.                 }
  2848.             }
  2849.             return array_values($series);
  2850.         };
  2851.         $purchaseOrderTotal = (float) $conn->fetchOne("
  2852.             SELECT COALESCE(SUM(CAST(COALESCE(NULLIF(po_amount, ''), 0) AS DECIMAL(15,2))), 0)
  2853.             FROM purchase_order
  2854.             WHERE company_id = :companyId AND status = 1 AND approved = 1
  2855.         ", ['companyId' => $companyId]);
  2856.         $purchaseInvoiceTotal = (float) $conn->fetchOne("
  2857.             SELECT COALESCE(SUM(CAST(COALESCE(NULLIF(invoice_amount, ''), 0) AS DECIMAL(15,2))), 0)
  2858.             FROM purchase_invoice
  2859.             WHERE company_id = :companyId AND status = 1 AND approved = 1
  2860.         ", ['companyId' => $companyId]);
  2861.         $purchasePaidTotal = (float) $conn->fetchOne("
  2862.             SELECT COALESCE(SUM(CAST(COALESCE(NULLIF(paid_amount, ''), 0) AS DECIMAL(15,2))), 0)
  2863.             FROM purchase_invoice
  2864.             WHERE company_id = :companyId AND status = 1 AND approved = 1
  2865.         ", ['companyId' => $companyId]);
  2866.         $purchaseRequisitionCount = (int) $conn->fetchOne("
  2867.             SELECT COUNT(*)
  2868.             FROM purchase_requisition
  2869.             WHERE company_id = :companyId AND status = 1
  2870.         ", ['companyId' => $companyId]);
  2871.         $purchaseOrderCount = (int) $conn->fetchOne("
  2872.             SELECT COUNT(*)
  2873.             FROM purchase_order
  2874.             WHERE company_id = :companyId AND status = 1 AND approved = 1
  2875.         ", ['companyId' => $companyId]);
  2876.         $purchaseInvoiceCount = (int) $conn->fetchOne("
  2877.             SELECT COUNT(*)
  2878.             FROM purchase_invoice
  2879.             WHERE company_id = :companyId AND status = 1 AND approved = 1
  2880.         ", ['companyId' => $companyId]);
  2881.         $pendingPurchaseRequisitionCount = (int) $conn->fetchOne("
  2882.             SELECT COUNT(*)
  2883.             FROM purchase_requisition
  2884.             WHERE company_id = :companyId AND status = 1 AND COALESCE(approved, 0) = 0
  2885.         ", ['companyId' => $companyId]);
  2886.         $pendingPurchaseOrderCount = (int) $conn->fetchOne("
  2887.             SELECT COUNT(*)
  2888.             FROM purchase_order
  2889.             WHERE company_id = :companyId AND status = 1 AND COALESCE(approved, 0) = 0
  2890.         ", ['companyId' => $companyId]);
  2891.         $pendingPurchaseInvoiceCount = (int) $conn->fetchOne("
  2892.             SELECT COUNT(*)
  2893.             FROM purchase_invoice
  2894.             WHERE company_id = :companyId AND status = 1 AND COALESCE(approved, 0) = 0
  2895.         ", ['companyId' => $companyId]);
  2896.         $supplierCount = (int) $conn->fetchOne("
  2897.             SELECT COUNT(DISTINCT supplier_id)
  2898.             FROM purchase_order
  2899.             WHERE company_id = :companyId AND status = 1 AND approved = 1
  2900.         ", ['companyId' => $companyId]);
  2901.         $topSuppliers $conn->fetchAllAssociative("
  2902.             SELECT po.supplier_id, s.supplier_name, COALESCE(SUM(CAST(COALESCE(NULLIF(po.po_amount, ''), 0) AS DECIMAL(15,2))), 0) AS total
  2903.             FROM purchase_order po
  2904.             LEFT JOIN acc_suppliers s ON s.supplier_id = po.supplier_id
  2905.             WHERE po.company_id = :companyId AND po.status = 1 AND po.approved = 1
  2906.             GROUP BY po.supplier_id, s.supplier_name
  2907.             ORDER BY total DESC
  2908.             LIMIT 5
  2909.         ", ['companyId' => $companyId]);
  2910.         $topSupplierTotal 0;
  2911.         foreach ($topSuppliers as $row) {
  2912.             $topSupplierTotal += (float) $row['total'];
  2913.         }
  2914.         $funnelBase max($purchaseRequisitionCount$purchaseOrderCount$purchaseInvoiceCount1);
  2915.         $paidCoverage $purchaseInvoiceTotal ? ($purchasePaidTotal $purchaseInvoiceTotal) * 100 0;
  2916.         return array(
  2917.             'kpis' => array(
  2918.                 array('label' => 'Purchase Orders''value' => $purchaseOrderCount'note' => 'Approved and active''icon' => 'shopping-cart''color' => 'blue',
  2919.                     'route' => 'purchase_orders''hint' => 'Approved, active purchase orders. Opens the Purchase Order list.'),
  2920.                 array('label' => 'Invoice Value''value' => $purchaseInvoiceTotal'note' => 'Billed through the period''icon' => 'file-text''color' => 'green',
  2921.                     'route' => 'purchase_invoices''hint' => 'Sum of invoice_amount over approved purchase invoices. Opens the full Purchase Invoice list.'),
  2922.                 array('label' => 'Paid Value''value' => $purchasePaidTotal'note' => 'Settled to suppliers''icon' => 'check-circle''color' => 'teal',
  2923.                     'route' => 'purchase_invoices''hint' => 'Sum of paid_amount actually recorded against approved purchase invoices. Opens the Purchase Invoice list.'),
  2924.                 array('label' => 'Outstanding Due''value' => max($purchaseInvoiceTotal $purchasePaidTotal0), 'note' => 'Open supplier liability''icon' => 'hourglass-half''color' => 'red',
  2925.                     'route' => 'purchase_invoices''hint' => 'Invoice Value minus payments actually recorded, floored at zero. Opens the Purchase Invoice list.'),
  2926.                 // COUNT(DISTINCT supplier_id) over approved POs â€” suppliers TRANSACTED
  2927.                 // WITH, not the supplier master. The destination list is a superset.
  2928.                 array('label' => 'Suppliers''value' => $supplierCount'note' => 'Active vendor base''icon' => 'building''color' => 'amber',
  2929.                     'route' => 'supplier_list''hint' => 'Distinct suppliers on approved purchase orders â€” not the size of the supplier master. Opens the Supplier list, which is larger.'),
  2930.                 array('label' => 'Open Requisitions''value' => $pendingPurchaseRequisitionCount'note' => 'Waiting for movement''icon' => 'tasks''color' => 'slate',
  2931.                     'route' => 'pr_list''hint' => 'Active purchase requisitions not yet approved. Opens the Purchase Requisition list.'),
  2932.             ),
  2933.             'pending_total' => $pendingPurchaseRequisitionCount $pendingPurchaseOrderCount $pendingPurchaseInvoiceCount,
  2934.             'pending_items' => array(
  2935.                 array('label' => 'Requisitions''value' => $pendingPurchaseRequisitionCount'note' => 'Needs buy-side review'),
  2936.                 array('label' => 'Purchase Orders''value' => $pendingPurchaseOrderCount'note' => 'Waiting for approval'),
  2937.                 array('label' => 'Purchase Invoices''value' => $pendingPurchaseInvoiceCount'note' => 'Pending matching'),
  2938.             ),
  2939.             'hero' => array(
  2940.                 'labels' => $monthLabels,
  2941.                 'series' => array(
  2942.                     array('label' => 'PO Value''values' => $seriesFromRows($poTrendRows$monthKeys), 'color' => '#3D7DB8''fill' => 'rgba(61,125,184,0.14)'),
  2943.                     array('label' => 'Invoice Value''values' => $seriesFromRows($invoiceTrendRows$monthKeys), 'color' => '#4BAA6B''fill' => 'rgba(75,170,107,0.14)'),
  2944.                     array('label' => 'Paid Value''values' => $seriesFromRows($paidTrendRows$monthKeys), 'color' => '#2F9E91''fill' => 'rgba(47,158,145,0.14)'),
  2945.                 ),
  2946.             ),
  2947.             'hero_summary' => array(
  2948.                 'headline' => $purchaseInvoiceTotal round($paidCoverage1) . '%' '0%',
  2949.                 'headline_label' => 'Payment coverage',
  2950.                 'subhead' => 'Paid ' round($paidCoverage1) . '% of billed value',
  2951.             ),
  2952.             'snapshot' => array(
  2953.                 'label' => 'Procurement Health',
  2954.                 'ring_value' => round($paidCoverage1),
  2955.                 'ring_note' => 'Invoice coverage',
  2956.                 'metrics' => array(
  2957.                     array('label' => 'Requisition to PO''value' => $purchaseRequisitionCount round(($purchaseOrderCount $purchaseRequisitionCount) * 1001) . '%' '0%''note' => 'Flow conversion'),
  2958.                     array('label' => 'Average PO Size''value' => $purchaseOrderCount number_format($purchaseOrderTotal $purchaseOrderCount0'.'',') : '0''note' => 'Approved order value'),
  2959.                     array('label' => 'Due Ratio''value' => $purchaseInvoiceTotal round((max($purchaseInvoiceTotal $purchasePaidTotal0) / $purchaseInvoiceTotal) * 1001) . '%' '0%''note' => 'Open liability share'),
  2960.                     array('label' => 'Supplier Concentration''value' => $purchaseOrderTotal round(($topSupplierTotal $purchaseOrderTotal) * 1001) . '%' '0%''note' => 'Top-5 spend share'),
  2961.                 ),
  2962.             ),
  2963.             'lower_cards' => array(
  2964.                 array(
  2965.                     'title' => 'Pipeline Atlas',
  2966.                     'subtitle' => 'Requisition to payment flow',
  2967.                     'type' => 'pipeline',
  2968.                     'items' => array(
  2969.                         array('label' => 'Requisitions''value' => $purchaseRequisitionCount'note' => 'Planning demand'),
  2970.                         array('label' => 'Purchase Orders''value' => $purchaseOrderCount'note' => 'Committed spend'),
  2971.                         array('label' => 'Purchase Invoices''value' => $purchaseInvoiceCount'note' => 'Vendor billing'),
  2972.                         array('label' => 'Settled''value' => (int) $conn->fetchOne("SELECT COUNT(*) FROM purchase_invoice WHERE company_id = :companyId AND status = 1 AND approved = 1 AND CAST(COALESCE(NULLIF(paid_amount, ''), 0) AS DECIMAL(15,2)) > 0", ['companyId' => $companyId]), 'note' => 'Cash released'),
  2973.                     ),
  2974.                     'base' => $funnelBase,
  2975.                 ),
  2976.                 array(
  2977.                     'title' => 'Supplier Mix',
  2978.                     'subtitle' => 'Concentration by approved spend',
  2979.                     'type' => 'bars',
  2980.                     'items' => array_map(function ($row) use ($topSupplierTotal) {
  2981.                         $total = (float) $row['total'];
  2982.                         return array(
  2983.                             'label' => $row['supplier_name'] ?: ('Supplier #' $row['supplier_id']),
  2984.                             'value' => $total,
  2985.                             'bar' => $topSupplierTotal round(($total $topSupplierTotal) * 1001) : 0,
  2986.                             'note' => 'Approved spend share',
  2987.                         );
  2988.                     }, $topSuppliers),
  2989.                 ),
  2990.                 array(
  2991.                     'title' => 'Spend Lens',
  2992.                     'subtitle' => 'Analytical ratios that matter',
  2993.                     'type' => 'ratios',
  2994.                     'items' => array(
  2995.                         array('label' => 'Payment Coverage''value' => round($paidCoverage1) . '%''bar' => $paidCoverage'note' => 'Cash settled vs billed'),
  2996.                         array('label' => 'Requisition Coverage''value' => $purchaseRequisitionCount round(($purchaseOrderCount $purchaseRequisitionCount) * 1001) . '%' '0%''bar' => $purchaseRequisitionCount ? (($purchaseOrderCount $purchaseRequisitionCount) * 100) : 0'note' => 'POs created from requests'),
  2997.                         array('label' => 'Open Due''value' => number_format(max($purchaseInvoiceTotal $purchasePaidTotal0), 0'.'','), 'bar' => $purchaseInvoiceTotal ? ((max($purchaseInvoiceTotal $purchasePaidTotal0) / $purchaseInvoiceTotal) * 100) : 0'note' => 'Balance still outstanding'),
  2998.                     ),
  2999.                 ),
  3000.             ),
  3001.             'months' => $monthLabels
  3002.         );
  3003.     }
  3004.     private function buildInventoryDashboardAnalytics($em$companyId)
  3005.     {
  3006.         $conn $em->getConnection();
  3007.         $monthKeys = [];
  3008.         $monthLabels = [];
  3009.         for ($i 5$i >= 0$i--) {
  3010.             $month = new \DateTime('first day of this month');
  3011.             if ($i 0) {
  3012.                 $month->modify('-' $i ' month');
  3013.             }
  3014.             $monthKeys[] = $month->format('Y-m');
  3015.             $monthLabels[] = $month->format('M');
  3016.         }
  3017.         $receivedRows $conn->fetchAllAssociative("
  3018.             SELECT DATE_FORMAT(stock_received_note_date, '%Y-%m') AS month, COUNT(*) AS total
  3019.             FROM stock_received_note
  3020.             WHERE company_id = :companyId
  3021.               AND status = 1
  3022.               AND approved = 1
  3023.               AND stock_received_note_date >= DATE_SUB(CURDATE(), INTERVAL 5 MONTH)
  3024.             GROUP BY DATE_FORMAT(stock_received_note_date, '%Y-%m')
  3025.             ORDER BY month ASC
  3026.         ", ['companyId' => $companyId]);
  3027.         $transferRows $conn->fetchAllAssociative("
  3028.             SELECT DATE_FORMAT(stock_transfer_date, '%Y-%m') AS month, COUNT(*) AS total
  3029.             FROM stock_transfer
  3030.             WHERE company_id = :companyId
  3031.               AND status = 1
  3032.               AND approved = 1
  3033.               AND stock_transfer_date >= DATE_SUB(CURDATE(), INTERVAL 5 MONTH)
  3034.             GROUP BY DATE_FORMAT(stock_transfer_date, '%Y-%m')
  3035.             ORDER BY month ASC
  3036.         ", ['companyId' => $companyId]);
  3037.         $consumptionRows $conn->fetchAllAssociative("
  3038.             SELECT DATE_FORMAT(stock_consumption_note_date, '%Y-%m') AS month, COUNT(*) AS total
  3039.             FROM stock_consumption_note
  3040.             WHERE company_id = :companyId
  3041.               AND status = 1
  3042.               AND approved = 1
  3043.               AND stock_consumption_note_date >= DATE_SUB(CURDATE(), INTERVAL 5 MONTH)
  3044.             GROUP BY DATE_FORMAT(stock_consumption_note_date, '%Y-%m')
  3045.             ORDER BY month ASC
  3046.         ", ['companyId' => $companyId]);
  3047.         $seriesFromRows = function (array $rows, array $monthKeys) {
  3048.             $series array_fill_keys($monthKeys0);
  3049.             foreach ($rows as $row) {
  3050.                 $month $row['month'] ?? null;
  3051.                 if ($month !== null && array_key_exists($month$series)) {
  3052.                     $series[$month] = (float) $row['total'];
  3053.                 }
  3054.             }
  3055.             return array_values($series);
  3056.         };
  3057.         $skuCount = (int) $conn->fetchOne("
  3058.             SELECT COUNT(*)
  3059.             FROM inv_products
  3060.             WHERE company_id = :companyId AND status = 1
  3061.         ", ['companyId' => $companyId]);
  3062.         $totalUnits = (float) $conn->fetchOne("
  3063.             SELECT COALESCE(SUM(CAST(COALESCE(NULLIF(qty, ''), 0) AS DECIMAL(15,2))), 0)
  3064.             FROM inv_products
  3065.             WHERE company_id = :companyId AND status = 1
  3066.         ", ['companyId' => $companyId]);
  3067.         $stockValue = (float) $conn->fetchOne("
  3068.             SELECT COALESCE(SUM(CAST(COALESCE(NULLIF(qty, ''), 0) AS DECIMAL(15,2)) * CAST(COALESCE(NULLIF(curr_purchase_price, ''), 0) AS DECIMAL(15,2))), 0)
  3069.             FROM inv_products
  3070.             WHERE company_id = :companyId AND status = 1
  3071.         ", ['companyId' => $companyId]);
  3072.         $lowStockCount = (int) $conn->fetchOne("
  3073.             SELECT COUNT(*)
  3074.             FROM inv_products
  3075.             WHERE company_id = :companyId
  3076.               AND status = 1
  3077.               AND CAST(COALESCE(NULLIF(qty, ''), 0) AS DECIMAL(15,2)) <= CAST(COALESCE(NULLIF(reorder_level, ''), 0) AS DECIMAL(15,2))
  3078.               AND CAST(COALESCE(NULLIF(reorder_level, ''), 0) AS DECIMAL(15,2)) > 0
  3079.         ", ['companyId' => $companyId]);
  3080.         $zeroStockCount = (int) $conn->fetchOne("
  3081.             SELECT COUNT(*)
  3082.             FROM inv_products
  3083.             WHERE company_id = :companyId AND status = 1 AND CAST(COALESCE(NULLIF(qty, ''), 0) AS DECIMAL(15,2)) <= 0
  3084.         ", ['companyId' => $companyId]);
  3085.         $overstockCount = (int) $conn->fetchOne("
  3086.             SELECT COUNT(*)
  3087.             FROM inv_products
  3088.             WHERE company_id = :companyId
  3089.               AND status = 1
  3090.               AND CAST(COALESCE(NULLIF(reorder_level, ''), 0) AS DECIMAL(15,2)) > 0
  3091.               AND CAST(COALESCE(NULLIF(qty, ''), 0) AS DECIMAL(15,2)) > (CAST(COALESCE(NULLIF(reorder_level, ''), 0) AS DECIMAL(15,2)) * 3)
  3092.         ", ['companyId' => $companyId]);
  3093.         $warehouseCount = (int) $conn->fetchOne("
  3094.             SELECT COUNT(*)
  3095.             FROM warehouse
  3096.             WHERE company_id = :companyId AND status = 1
  3097.         ", ['companyId' => $companyId]);
  3098.         $receivedPending = (int) $conn->fetchOne("
  3099.             SELECT COUNT(*)
  3100.             FROM stock_received_note
  3101.             WHERE company_id = :companyId AND status = 1 AND COALESCE(approved, 0) = 0
  3102.         ", ['companyId' => $companyId]);
  3103.         $transferPending = (int) $conn->fetchOne("
  3104.             SELECT COUNT(*)
  3105.             FROM stock_transfer
  3106.             WHERE company_id = :companyId AND status = 1 AND COALESCE(approved, 0) = 0
  3107.         ", ['companyId' => $companyId]);
  3108.         $consumptionPending = (int) $conn->fetchOne("
  3109.             SELECT COUNT(*)
  3110.             FROM stock_consumption_note
  3111.             WHERE company_id = :companyId AND status = 1 AND COALESCE(approved, 0) = 0
  3112.         ", ['companyId' => $companyId]);
  3113.         $receivedCount = (int) $conn->fetchOne("
  3114.             SELECT COUNT(*)
  3115.             FROM stock_received_note
  3116.             WHERE company_id = :companyId AND status = 1 AND approved = 1
  3117.         ", ['companyId' => $companyId]);
  3118.         $transferCount = (int) $conn->fetchOne("
  3119.             SELECT COUNT(*)
  3120.             FROM stock_transfer
  3121.             WHERE company_id = :companyId AND status = 1 AND approved = 1
  3122.         ", ['companyId' => $companyId]);
  3123.         $consumptionCount = (int) $conn->fetchOne("
  3124.             SELECT COUNT(*)
  3125.             FROM stock_consumption_note
  3126.             WHERE company_id = :companyId AND status = 1 AND approved = 1
  3127.         ", ['companyId' => $companyId]);
  3128.         $warehouseMap = \ApplicationBundle\Modules\Inventory\Inventory::WarehouseList($em$companyId);
  3129.         $warehouseRows $conn->fetchAllAssociative("
  3130.             SELECT warehouse_id, COALESCE(SUM(CAST(COALESCE(NULLIF(qty, ''), 0) AS DECIMAL(15,2))), 0) AS total_qty,
  3131.                    COALESCE(SUM(CAST(COALESCE(NULLIF(qty, ''), 0) AS DECIMAL(15,2)) * CAST(COALESCE(NULLIF(curr_purchase_price, ''), 0) AS DECIMAL(15,2))), 0) AS total_value
  3132.             FROM inventory_storage
  3133.             WHERE company_id = :companyId
  3134.             GROUP BY warehouse_id
  3135.             ORDER BY total_value DESC
  3136.             LIMIT 5
  3137.         ", ['companyId' => $companyId]);
  3138.         $productRows $conn->fetchAllAssociative("
  3139.             SELECT s.product_id, p.name, p.reorder_level,
  3140.                    COALESCE(SUM(CAST(COALESCE(NULLIF(s.qty, ''), 0) AS DECIMAL(15,2))), 0) AS total_qty,
  3141.                    COALESCE(SUM(CAST(COALESCE(NULLIF(s.qty, ''), 0) AS DECIMAL(15,2)) * CAST(COALESCE(NULLIF(s.curr_purchase_price, ''), 0) AS DECIMAL(15,2))), 0) AS total_value
  3142.             FROM inventory_storage s
  3143.             LEFT JOIN inv_products p ON p.id = s.product_id
  3144.             WHERE s.company_id = :companyId
  3145.             GROUP BY s.product_id, p.name, p.reorder_level
  3146.             ORDER BY total_value DESC
  3147.             LIMIT 5
  3148.         ", ['companyId' => $companyId]);
  3149.         $movementBalance $receivedCount $consumptionCount;
  3150.         $healthIndex $skuCount max(0100 round(($lowStockCount $skuCount) * 100)) : 0;
  3151.         $reorderPressure $skuCount round(($lowStockCount $skuCount) * 1001) : 0;
  3152.         $stockCoverage $warehouseCount round($totalUnits $warehouseCount1) : 0;
  3153.         $topWarehouseTotal 0;
  3154.         foreach ($warehouseRows as $row) {
  3155.             $topWarehouseTotal += (float) $row['total_value'];
  3156.         }
  3157.         $topProductTotal 0;
  3158.         foreach ($productRows as $row) {
  3159.             $topProductTotal += (float) $row['total_value'];
  3160.         }
  3161.         return array(
  3162.             'kpis' => array(
  3163.                 array('label' => 'SKUs''value' => $skuCount'note' => 'Active item master''icon' => 'cube''color' => 'blue',
  3164.                     'route' => 'product_list''hint' => 'Active products in the item master. Opens the Product list.'),
  3165.                 array('label' => 'On-hand Units''value' => $totalUnits'note' => 'Current quantity snapshot''icon' => 'cubes''color' => 'green',
  3166.                     'route' => 'product_list''hint' => 'Sum of qty across active products. Opens the Product list those quantities come from.'),
  3167.                 array('label' => 'Stock Value''value' => $stockValue'note' => 'Book value at purchase cost''icon' => 'storage''color' => 'teal',
  3168.                     'route' => 'inventory_view''hint' => 'Sum of qty x curr_purchase_price across active products. Opens the Stock view.'),
  3169.                 array('label' => 'Low Stock SKUs''value' => $lowStockCount'note' => 'At or below reorder point''icon' => 'exclamation-triangle''color' => 'red',
  3170.                     'route' => 'product_list''hint' => 'Products whose qty is at or below a reorder level that has actually been set. Opens the full Product list.'),
  3171.                 // No warehouse LIST route exists (only add_subwarehouse and APIs), so this
  3172.                 // card stays a plain div rather than gaining a link that goes nowhere useful.
  3173.                 array('label' => 'Warehouses''value' => $warehouseCount'note' => 'Active storage nodes''icon' => 'warehouse''color' => 'amber'),
  3174.                 array('label' => 'Pending Docs''value' => $receivedPending $transferPending $consumptionPending'note' => 'Awaiting approval''icon' => 'hourglass-half''color' => 'slate',
  3175.                     'route' => 'pending_approval_list''hint' => 'Receipts + transfers + consumption notes awaiting approval. Opens My Approvals, which is scoped to YOU and so may show fewer.'),
  3176.             ),
  3177.             'pending_total' => $receivedPending $transferPending $consumptionPending,
  3178.             'pending_items' => array(
  3179.                 array('label' => 'Stock Received''value' => $receivedPending'note' => 'Incoming goods'),
  3180.                 array('label' => 'Stock Transfer''value' => $transferPending'note' => 'Warehouse movement'),
  3181.                 array('label' => 'Consumption Notes''value' => $consumptionPending'note' => 'Consumption posting'),
  3182.             ),
  3183.             'hero' => array(
  3184.                 'labels' => $monthLabels,
  3185.                 'series' => array(
  3186.                     array('label' => 'Received''values' => $seriesFromRows($receivedRows$monthKeys), 'color' => '#3D7DB8''fill' => 'rgba(61,125,184,0.14)'),
  3187.                     array('label' => 'Transfers''values' => $seriesFromRows($transferRows$monthKeys), 'color' => '#D4A843''fill' => 'rgba(212,168,67,0.14)'),
  3188.                     array('label' => 'Consumed''values' => $seriesFromRows($consumptionRows$monthKeys), 'color' => '#C05350''fill' => 'rgba(192,83,80,0.14)'),
  3189.                 ),
  3190.             ),
  3191.             'hero_summary' => array(
  3192.                 'headline' => $healthIndex '%',
  3193.                 'headline_label' => 'Health index',
  3194.                 'subhead' => 'Low stock pressure at ' $reorderPressure '%',
  3195.             ),
  3196.             'snapshot' => array(
  3197.                 'label' => 'Stock Health',
  3198.                 'ring_value' => $healthIndex,
  3199.                 'ring_note' => 'Health index',
  3200.                 'metrics' => array(
  3201.                     array('label' => 'Low Stock Pressure''value' => $reorderPressure '%''note' => 'At or under reorder'),
  3202.                     array('label' => 'Movement Balance''value' => $movementBalance'note' => 'Received minus consumed'),
  3203.                     array('label' => 'Avg Units / Warehouse''value' => $stockCoverage'note' => 'Distribution breadth'),
  3204.                     array('label' => 'Zero Stock SKUs''value' => $zeroStockCount'note' => 'Immediate attention'),
  3205.                 ),
  3206.             ),
  3207.             'lower_cards' => array(
  3208.                 array(
  3209.                     'title' => 'Reorder Radar',
  3210.                     'subtitle' => 'What needs intervention now',
  3211.                     'type' => 'radar',
  3212.                     'items' => array(
  3213.                         array('label' => 'Low Stock''value' => $lowStockCount'bar' => $skuCount ? (($lowStockCount $skuCount) * 100) : 0'note' => 'At reorder threshold'),
  3214.                         array('label' => 'Zero Stock''value' => $zeroStockCount'bar' => $skuCount ? (($zeroStockCount $skuCount) * 100) : 0'note' => 'Unavailable items'),
  3215.                         array('label' => 'Overstock''value' => $overstockCount'bar' => $skuCount ? (($overstockCount $skuCount) * 100) : 0'note' => 'Potential capital lock-up'),
  3216.                         array('label' => 'Movement Balance''value' => $movementBalance'bar' => max(0min(10050 + ($movementBalance 5))), 'note' => 'Inbound vs consumption'),
  3217.                     ),
  3218.                 ),
  3219.                 array(
  3220.                     'title' => 'Warehouse Atlas',
  3221.                     'subtitle' => 'Value concentration by store',
  3222.                     'type' => 'bars',
  3223.                     'items' => array_map(function ($row) use ($warehouseMap$topWarehouseTotal) {
  3224.                         $warehouseId = (int) $row['warehouse_id'];
  3225.                         $warehouseName = isset($warehouseMap[$warehouseId]['name']) ? $warehouseMap[$warehouseId]['name'] : ('Warehouse #' $warehouseId);
  3226.                         $total = (float) $row['total_value'];
  3227.                         return array(
  3228.                             'label' => $warehouseName,
  3229.                             'value' => $total,
  3230.                             'bar' => $topWarehouseTotal round(($total $topWarehouseTotal) * 1001) : 0,
  3231.                             'note' => 'Stock value share',
  3232.                         );
  3233.                     }, $warehouseRows),
  3234.                 ),
  3235.                 array(
  3236.                     'title' => 'Value Lens',
  3237.                     'subtitle' => 'Highest value stock pockets',
  3238.                     'type' => 'products',
  3239.                     'items' => array_map(function ($row) use ($topProductTotal) {
  3240.                         $total = (float) $row['total_value'];
  3241.                         $reorderLevel = isset($row['reorder_level']) ? (float) $row['reorder_level'] : 0;
  3242.                         return array(
  3243.                             'label' => $row['name'] ?: ('SKU #' $row['product_id']),
  3244.                             'value' => $total,
  3245.                             'bar' => $topProductTotal round(($total $topProductTotal) * 1001) : 0,
  3246.                             'note' => 'Reorder level ' number_format($reorderLevel0'.'','),
  3247.                         );
  3248.                     }, $productRows),
  3249.                 ),
  3250.             ),
  3251.             'months' => $monthLabels
  3252.         );
  3253.     }
  3254.     public function indexServiceAction(Request $request)
  3255.     {
  3256.         $session $request->getSession();
  3257.         $dashboardDataForUser = [];
  3258.         $em $this->getDoctrine()->getManager();
  3259.         $companyId $this->getLoggedUserCompanyId($request);
  3260.         $userId $request->getSession()->get(UserConstants::USER_ID);
  3261.         $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  3262.             array(
  3263.                 'CompanyId' => $companyId,
  3264.                 'userId' => $userId,
  3265.                 'status' => GeneralConstant::ACTIVE
  3266.             ),
  3267.             array(
  3268.                 'sequence' => 'ASC'
  3269.             )
  3270.         );
  3271.         if (empty($dbQuery))   ///now get the defaults
  3272.             $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  3273.                 array(
  3274.                     'CompanyId' => $companyId,
  3275.                     //                    'userId'=>$userId,
  3276.                     'defaultBoxFlag' => 1,
  3277.                     'status' => GeneralConstant::ACTIVE
  3278.                 ),
  3279.                 array(
  3280.                     'sequence' => 'ASC'
  3281.                 )
  3282.             );
  3283.         foreach ($dbQuery as $entry) {
  3284.             $dashboardDataForUser[] = array(
  3285.                 'id' => $entry->getId(),
  3286.                 'widgetId' => $entry->getId(),
  3287.                 'widgetSequence' => $entry->getSequence(),
  3288.                 'widgetStatus' => $entry->getStatus(),
  3289.                 'widgetData' => json_decode($entry->getData(), true),
  3290.                 'defaultBoxFlag' => $entry->getDefaultBoxFlag(),
  3291.                 'widgetSizeTiny' => $entry->getSizeTiny(),
  3292.                 'widgetSizeSmall' => $entry->getSizeSmall(),
  3293.                 'widgetSizeMedium' => $entry->getSizeMedium(),
  3294.                 'widgetSizeLarge' => $entry->getSizeLarge(),
  3295.                 'refreshInterval' => $entry->getRefreshInterval(),
  3296.             );
  3297.         }
  3298.         return $this->render(
  3299.             '@Application/pages/dashboard/index_sales.html.twig',
  3300.             array(
  3301.                 'page_title' => 'Sales Dashboard',
  3302.                 'dashboardDataForUser' => $dashboardDataForUser
  3303.             )
  3304.         );
  3305.     }
  3306.     public function modifyDashboardAction(Request $request)
  3307.     {
  3308.         $session $request->getSession();
  3309.         $em $this->getDoctrine()->getManager();
  3310.         $companyId $this->getLoggedUserCompanyId($request);
  3311.         $userId $request->getSession()->get(UserConstants::USER_ID);
  3312.         if ($request->isMethod('post')) {
  3313.             //update dashboard data
  3314.             if ($request->request->has('widgetId')) {
  3315.                 foreach ($request->request->get('widgetId') as $k => $v) {
  3316.                     if ($v != 0) {
  3317.                         //exists sso edit
  3318.                         $widget $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findOneBy(
  3319.                             array(
  3320.                                 'id' => $v,
  3321.                             )
  3322.                         );
  3323.                     } else
  3324.                         $widget = new DashboardWidget();
  3325.                     $widget->setData($request->request->get('widgetData')[$k]);
  3326.                     $widget->setSequence($request->request->get('widgetSequence')[$k]);
  3327.                     $widget->setStatus($request->request->has('widgetStatus') ? $request->request->get('widgetStatus')[$k] : GeneralConstant::ACTIVE);
  3328.                     $widget->setUserId($userId);
  3329.                     $widget->setCompanyId($companyId);
  3330.                     $widget->setDefaultBoxFlag($request->request->has('defaultBoxFlag') ? $request->request->get('defaultBoxFlag')[$k] : 0);
  3331.                     if ($v == 0)
  3332.                         $em->persist($widget);
  3333.                     $em->flush();
  3334.                 }
  3335.             }
  3336.         }
  3337.         $dashboardDataForUser = [];
  3338.         $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  3339.             array(
  3340.                 'CompanyId' => $companyId,
  3341.                 'userId' => $userId,
  3342.                 'status' => GeneralConstant::ACTIVE
  3343.             )
  3344.         );
  3345.         if (empty($dbQuery))   ///now get the defaults
  3346.             $dbQuery $em->getRepository("ApplicationBundle\\Entity\\DashboardWidget")->findBy(
  3347.                 array(
  3348.                     'CompanyId' => $companyId,
  3349.                     //                    'userId'=>$userId,
  3350.                     'defaultBoxFlag' => 1,
  3351.                     'status' => GeneralConstant::ACTIVE
  3352.                 )
  3353.             );
  3354.         foreach ($dbQuery as $entry) {
  3355.             $dashboardDataForUser[] = array(
  3356.                 'id' => $entry->getId(),
  3357.                 'widgetId' => $entry->getId(),
  3358.                 'widgetSequence' => $entry->getSequence(),
  3359.                 'widgetStatus' => $entry->getStatus(),
  3360.                 'widgetData' => $entry->getData(),
  3361.                 'defaultBoxFlag' => $entry->getDefaultBoxFlag(),
  3362.                 'widgetSizeTiny' => $entry->getSizeTiny(),
  3363.                 'widgetSizeSmall' => $entry->getSizeSmall(),
  3364.                 'widgetSizeMedium' => $entry->getSizeMedium(),
  3365.                 'widgetSizeLarge' => $entry->getSizeLarge(),
  3366.                 'refreshInterval' => $entry->getRefreshInterval(),
  3367.             );
  3368.         }
  3369.         //1st try to see if any exists
  3370.         return $this->render(
  3371.             '@Application/pages/dashboard/index_sales.html.twig',
  3372.             array(
  3373.                 'page_title' => 'Modify Dashboard'
  3374.             )
  3375.         );
  3376.     }
  3377.     public function ChangeCompanyDashboardAction(Request $request$id 1)
  3378.     {
  3379.         $session $request->getSession();
  3380.         if ($request->query->has('sys_admin_panel'))
  3381.             return $this->redirectToRoute('system_admin_dashboard');
  3382.         else {
  3383.             $session->set(UserConstants::USER_COMPANY_ID$id);
  3384.             return $this->redirectToRoute('dashboard');
  3385.         }
  3386.     }
  3387.     public function ChangeLeftPanelDisplayStatusAction(Request $request)
  3388.     {
  3389.         $session $request->getSession();
  3390.         $curr_status 1;
  3391.         if ($session->has('HIDE_LEFT_PANEL'))
  3392.             $curr_status $session->get('HIDE_LEFT_PANEL');
  3393.         if ($curr_status == 1)
  3394.             $curr_status 0;
  3395.         else
  3396.             $curr_status 1;
  3397.         $session->set('HIDE_LEFT_PANEL'$curr_status);
  3398.         //            return $this->redirectToRoute('dashboard');
  3399.         return new Response($curr_status);
  3400.     }
  3401.     public function PermissionDeniedAction(Request $request)
  3402.     {
  3403.         $session $request->getSession();
  3404.         // Generic::debugMessage($session);
  3405.         return $this->render(
  3406.             '@System/pages/permission_denied.html.twig',
  3407.             array(
  3408.                 'page_title' => 'Permission Denied'
  3409.             )
  3410.         );
  3411.     }
  3412.     public function MyDocumentsAction(Request $request)
  3413.     {
  3414.         $session $request->getSession();
  3415.         $em $this->getDoctrine()->getManager();
  3416.         /* DATE FILTER â€” issue register #14. A month token wins over a hand-typed range
  3417.            (register #27: "i need another filter field where i can select only Month option"),
  3418.            and an INVALID range is reported rather than silently ignored â€” a filter that
  3419.            quietly drops your input is worse than one that says no. */
  3420.         $period PeriodFilterCore::resolve(
  3421.             $request->query->get('month'''),
  3422.             $request->query->get('start_date'''),
  3423.             $request->query->get('end_date''')
  3424.         );
  3425.         $periodError $period['ok'] ? '' $period['reason'];
  3426.         $data MiscActions::getDocumentsByUserId(
  3427.             $em,
  3428.             $session->get(UserConstants::USER_ID),
  3429.             $period['ok'] ? $period['start'] : '',
  3430.             $period['ok'] ? $period['end'] : ''
  3431.         );
  3432.         // DOC-001: the view calls path(item.documentViewPathName); if an entity's
  3433.         // registered view-route name is stale/unregistered, path() throws and the
  3434.         // whole page 500s the moment a user owns a document of that type. Validate
  3435.         // each route against the router and fall back to a safe one.
  3436.         $routes $this->container->get('router')->getRouteCollection();
  3437.         if (is_array($data)) {
  3438.             foreach ($data as $k => $item) {
  3439.                 $rn = isset($item['documentViewPathName']) ? $item['documentViewPathName'] : '';
  3440.                 if ($rn === '' || $routes->get($rn) === null) {
  3441.                     $data[$k]['documentViewPathName'] = 'dashboard';
  3442.                 }
  3443.             }
  3444.         }
  3445.         return $this->render(
  3446.             '@Application/pages/dashboard/my_documents.html.twig',
  3447.             array(
  3448.                 'page_title' => 'My Documents',
  3449.                 'data' => $data,
  3450.                 'filter_month' => $request->query->get('month'''),
  3451.                 'filter_start' => $request->query->get('start_date'''),
  3452.                 'filter_end' => $request->query->get('end_date'''),
  3453.                 'filter_label' => $period['ok'] ? $period['label'] : '',
  3454.                 'filter_error' => $periodError,
  3455.                 'month_options' => PeriodFilterCore::recentMonths(date('Y-m-d'), 18),
  3456.             )
  3457.         );
  3458.     }
  3459.     //     public function MyDocumentsListForAppAction(Request $request)
  3460.     //     {
  3461.     //         $session = $request->getSession();
  3462.     //         $em = $this->getDoctrine()->getManager();
  3463.     //         $absoluteUrlList = [];
  3464.     //         foreach (GeneralConstant::$Entity_list_details as $e => $d) {
  3465.     //             if (isset($d['entity_print_route_path_name']))
  3466.     //                 $absoluteUrlList[$e] = $this->generateUrl($d['entity_print_route_path_name'], [], UrlGenerator::ABSOLUTE_URL);
  3467.     //         }
  3468.     //         $data = MiscActions::getDocumentsByUserIdForApp($em, $session->get(UserConstants::USER_ID), 1, $absoluteUrlList);
  3469.     //         // Generic::debugMessage($session);
  3470.     //         return new JsonResponse(array(
  3471.     //             'data' => $data
  3472.     //         ));
  3473.     // //        return $this->render('ApplicationBundle:pages/dashboard:my_documents.html.twig',
  3474.     // //            array(
  3475.     // //                'page_title' => 'My Documents',
  3476.     // //                'data' => $data
  3477.     // //            )
  3478.     // //        );
  3479.     //     }
  3480.     public function MyDocumentsListForAppAction(Request $request)
  3481.     {
  3482.         $session $request->getSession();
  3483.         $em $this->getDoctrine()->getManager();
  3484.         // Build absolute URL list
  3485.         $absoluteUrlList = [];
  3486.         foreach (GeneralConstant::$Entity_list_details as $e => $d) {
  3487.             if (isset($d['entity_print_route_path_name'])) {
  3488.                 $absoluteUrlList[$e] = $this->generateUrl($d['entity_print_route_path_name'], [], UrlGenerator::ABSOLUTE_URL);
  3489.             }
  3490.         }
  3491.         // Extract pagination parameters from the request
  3492.         $page $request->query->get('page''_UNSET_');
  3493.         $offset $request->query->get('offset'0);
  3494.         $limit $request->query->get('limit'10); // default limit is 10
  3495.         // Call the document list method with pagination
  3496.         return new JsonResponse(
  3497.             MiscActions::getDocumentsByUserIdForApp(
  3498.                 $em,
  3499.                 $session->get(UserConstants::USER_ID),
  3500.                 1,
  3501.                 $absoluteUrlList,
  3502.                 $page,
  3503.                 $offset,
  3504.                 $limit
  3505.             )
  3506.         );
  3507.     }
  3508.     public function ShowExceptionAction(Request $requestFlattenException $exceptionDebugLoggerInterface $logger null)
  3509.     {
  3510.         $session $request->getSession();
  3511.         $em $this->getDoctrine()->getManager();
  3512.         // Generic::debugMessage($session);
  3513.         //        $currentContent = $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1));
  3514.         //        $showException = $request->attributes->get('showException', $this->debug); // As opposed to an additional parameter, this maintains BC
  3515.         $code $exception->getStatusCode();
  3516.         //        $data = MiscActions::getDocumentsByUserId($em, $session->get(UserConstants::USER_ID));
  3517.         return $this->render(
  3518.             '@Application/pages/error/error_' $code '.html.twig',
  3519.             array(
  3520.                 'page_title' => 'Sorry',
  3521.                 //                'data' => $data
  3522.             )
  3523.         );
  3524.     }
  3525.     public function NotificationAction(Request $request)
  3526.     {
  3527.         $session $request->getSession();
  3528.         //'error', 'success', 'alert', 'information', 'warning', 'confirm'
  3529.         $themes = array(
  3530.             'error' => 'bg-red',
  3531.             'success' => 'bg-green',
  3532.             'alert' => 'bg-purple',
  3533.             'information' => 'bg-grey',
  3534.             'warning' => 'bg-orange',
  3535.             'confirm' => 'bg-blue',
  3536.         );
  3537.         $fa = array(
  3538.             'error' => 'fa fa-ban',
  3539.             'success' => 'fa fa-check',
  3540.             'alert' => 'fa fa-envelope',
  3541.             'information' => 'fa fa-comments',
  3542.             'warning' => 'fa fa-warning',
  3543.             'confirm' => 'fa fa-crosshairs',
  3544.         );
  3545.         // Generic::debugMessage($session);
  3546.         // â”€â”€ DB-first notification list â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
  3547.         // History is sourced from entity_notification (persistent DB), not the
  3548.         // socket server's in-memory cache which is lost on restart / missing the
  3549.         // /get_all_notification endpoint entirely.
  3550.         $cgEm   $this->getDoctrine()->getManager('company_group');
  3551.         $userId = (int) $request->getSession()->get(UserConstants::USER_ID0);
  3552.         $companyId = (int) $request->getSession()->get(UserConstants::USER_COMPANY_ID0);
  3553.         $filterUnread $request->query->get('filter') === 'unread';
  3554.         $qb $cgEm->getRepository('CompanyGroupBundle\\Entity\\EntityNotification')
  3555.             ->createQueryBuilder('n')
  3556.             ->where('n.userId = :uid')
  3557.             ->setParameter('uid'$userId);
  3558.         if ($filterUnread) {
  3559.             $qb->andWhere('n.seenFlag = 0');
  3560.         }
  3561.         $notifications $qb
  3562.             ->orderBy('n.notificationTs''DESC')
  3563.             ->setMaxResults(100)
  3564.             ->getQuery()
  3565.             ->getResult();
  3566.         $unreadCount = (int) $cgEm->getConnection()->fetchOne(
  3567.             'SELECT COUNT(*) FROM entity_notification WHERE user_id = :uid AND seen_flag = 0',
  3568.             ['uid' => $userId]
  3569.         );
  3570.         return $this->render(
  3571.             '@Application/pages/dashboard/notification.html.twig',
  3572.             array(
  3573.                 'page_title'    => 'Notifications',
  3574.                 'dt'            => $notifications,
  3575.                 'unreadCount'   => $unreadCount,
  3576.                 'filterUnread'  => $filterUnread,
  3577.                 'themes'        => $themes,
  3578.                 'fa'            => $fa,
  3579.             )
  3580.         );
  3581.     }
  3582.     public function NotificationDetailAction(Request $request$id 0)
  3583.     {
  3584.         $em $this->getDoctrine()->getManager('company_group');
  3585.         $notification $em->getRepository('CompanyGroupBundle\\Entity\\EntityNotification')->find($id);
  3586.         if (!$notification) {
  3587.             return $this->render(
  3588.                 '@Application/pages/dashboard/notification_detail.html.twig',
  3589.                 array(
  3590.                     'page_title' => 'Notification Detail',
  3591.                     'notification' => null,
  3592.                     'detailError' => 'Notification not found.',
  3593.                 )
  3594.             );
  3595.         }
  3596.         if ((int) $notification->getSeenFlag() !== 1) {
  3597.             $notification->setSeenFlag(1);
  3598.         }
  3599.         if ((int) $notification->getReadFlag() !== 1) {
  3600.             $notification->setReadFlag(1);
  3601.         }
  3602.         $em->flush();
  3603.         return $this->render(
  3604.             '@Application/pages/dashboard/notification_detail.html.twig',
  3605.             array(
  3606.                 'page_title' => 'Notification Detail',
  3607.                 'notification' => $notification,
  3608.                 'detailError' => '',
  3609.             )
  3610.         );
  3611.     }
  3612.     public function EditAccountAction(Request $request)
  3613.     {
  3614.         $session $request->getSession();
  3615.         //'error', 'success', 'alert', 'information', 'warning', 'confirm'
  3616.         $themes = array(
  3617.             'error' => 'bg-red',
  3618.             'success' => 'bg-green',
  3619.             'alert' => 'bg-purple',
  3620.             'information' => 'bg-aqua',
  3621.             'warning' => 'bg-orange',
  3622.             'confirm' => 'bg-blue',
  3623.         );
  3624.         $fa = array(
  3625.             'error' => 'fa fa-ban',
  3626.             'success' => 'fa fa-check',
  3627.             'alert' => 'fa fa-envelope',
  3628.             'information' => 'fa fa-comments',
  3629.             'warning' => 'fa fa-warning',
  3630.             'confirm' => 'fa fa-crosshairs',
  3631.         );
  3632.         $em $this->getDoctrine()->getManager();
  3633.         $g_path '';
  3634.         if ($request->isMethod('POST')) {
  3635.             $post $request->request;
  3636.             $path "";
  3637.             foreach ($request->files as $uploadedFile) {
  3638.                 if ($uploadedFile != null) {
  3639.                     $fileName md5(uniqid()) . '.' $uploadedFile->guessExtension();
  3640.                     $path $fileName;
  3641.                     $upl_dir $this->container->getParameter('kernel.root_dir') . '/../web/uploads/FileUploads/' $request->request->get('userId') . '/';
  3642.                     if (!file_exists($upl_dir)) {
  3643.                         mkdir($upl_dir0777true);
  3644.                     }
  3645.                     $file $uploadedFile->move($upl_dir$path);
  3646.                 }
  3647.             }
  3648.             if ($path != "")
  3649.                 $file_path 'uploads/FileUploads/' $request->request->get('userId') . '/' $path;
  3650.             $g_path $this->container->getParameter('kernel.root_dir') . '/../web/uploads/FileUploads/' $request->request->get('userId') . '/' $path;
  3651.             //            $img_file = file_get_contents($g_path);
  3652.             //            $image_data=base64_encode($img_file);
  3653.             //            $encoded_data=System::encryptSignature($image_data,$request->request->get('approvalHash'));
  3654.             $query_here $this->getDoctrine()
  3655.                 ->getRepository('ApplicationBundle\\Entity\\SysUser')
  3656.                 ->findOneBy(
  3657.                     array('userId' => $request->request->get('userId'))
  3658.                 );
  3659.             if ($query_here) {
  3660.                 $new $query_here;
  3661.                 if ($path != "") {
  3662.                     if ($request->request->has('check_pp')) {
  3663.                         $new->setImage($file_path);
  3664.                         $session->set(UserConstants::USER_IMAGE$new->getImage());
  3665.                     } else
  3666.                         $new->setImage('');
  3667.                 }
  3668.                 $new->setName($request->request->get('name'));
  3669.                 $session->set(UserConstants::USER_NAME$request->request->get('name'));
  3670.                 //now password
  3671.                 if ($request->request->get('oldPass') != '') {
  3672.                     //1st check if old pass valid
  3673.                     if (!$this->container->get('app.legacy_password_service')->verifyWithSalt($new->getPassword(), $request->request->get('oldPass'), $new->getSalt())) {
  3674.                         $this->addFlash(
  3675.                             'error',
  3676.                             'Your Old Password Was Wrong'
  3677.                         );
  3678.                     } else {
  3679.                         //old pass valid so now check if neww passes matches
  3680.                         if ($request->request->get('newPass') == $request->request->get('newPassAgain')) {
  3681.                             $new->setSalt(uniqid(mt_rand()));
  3682.                             $password $this->container->get('app.legacy_password_service')->hashWithSalt($request->request->get('newPass'), $new->getSalt());
  3683.                             $new->setPassword($password);
  3684.                             $em->flush();
  3685.                         } else {
  3686.                             $this->addFlash(
  3687.                                 'error',
  3688.                                 'Passwords Did not Match'
  3689.                             );
  3690.                         }
  3691.                     }
  3692.                 }
  3693.             } else {
  3694.                 //                    $new=new EncryptedSignature();
  3695.                 //                    $new->setData($encoded_data);
  3696.                 //                    $new->setUserId($request->request->get('userId'));
  3697.                 //                    $em->persist($new);
  3698.             }
  3699.             $em->flush();
  3700.             //            now deleting the file
  3701.         }
  3702.         $user_data Users::getUserInfoByLoginId($em$this->getLoggedUserLoginId($request));
  3703.         // Generic::debugMessage($session);
  3704.         return $this->render(
  3705.             '@System/pages/settings/edit_account.html.twig',
  3706.             array(
  3707.                 'page_title' => 'Edit Account',
  3708.                 'user_data' => $user_data,
  3709.                 //                'dt'=>json_decode(System::GetAllNotification($request->getSession()->get(UserConstants::USER_ID)),true),
  3710.                 'themes' => $themes,
  3711.                 'fa' => $fa,
  3712.             )
  3713.         );
  3714.     }
  3715.     public function indexApplicantAction(Request $request)
  3716.     {
  3717.         $systemType $this->container->hasParameter('system_type') ? $this->container->getParameter('system_type') : '_ERP_';
  3718.         $twig_file '@Application/pages/login/applicant_login.html.twig';
  3719.         $session $request->getSession();
  3720.         if ($systemType == '_BUDDYBEE_') {
  3721.             if ($session->get('buddybeeAdminLevel'0) > 1)
  3722.                 return $this->redirectToRoute("buddybee_admin_dashboard", []);
  3723.             elseif ($session->get('isConsultant') == 1)
  3724.                 return $this->redirectToRoute("consultant_dashboard", []);
  3725.             else
  3726.                 return $this->redirectToRoute("student_dashboard", []);
  3727.         } elseif ($systemType == '_CENTRAL_') {
  3728.             return $this->render(
  3729.                 '@Application/pages/dashboard/index_applicant.html.twig',
  3730.                 array(
  3731.                     'page_title' => 'Applicant Dashboard'
  3732.                 )
  3733.             );
  3734.         } else
  3735.             return $this->render(
  3736.                 '@Application/pages/dashboard/consultant_dashboard.html.twig',
  3737.                 array(
  3738.                     'page_title' => 'Applicant Dashboard'
  3739.                 )
  3740.             );
  3741.     }
  3742.     public function indexCentralLandingAction(Request $request)
  3743.     {
  3744.         $session $request->getSession();
  3745.         $userAccessList $session->get('userAccessList', []);
  3746.         $companyNames array_map(function ($company) {
  3747.             return $company['companyName'];
  3748.         }, $userAccessList);
  3749.         if ($request->isMethod('POST')) {
  3750.             $employeeId $request->request->get('employee_id');
  3751.             $companyName $request->request->get('company_name');
  3752.             if ($employeeId && $companyName) {
  3753.                 return new JsonResponse([
  3754.                     'status' => 'success',
  3755.                     'message' => 'Data received successfully',
  3756.                     'employee_id' => $employeeId,
  3757.                     'company_name' => $companyName,
  3758.                 ]);
  3759.             } else {
  3760.                 return new JsonResponse([
  3761.                     'status' => 'error',
  3762.                     'message' => 'Employee ID or Company Name is missing',
  3763.                 ]);
  3764.             }
  3765.         }
  3766.         // If the request is not a POST request, render the normal page
  3767.         return $this->render(
  3768.             '@Application/pages/dashboard/index_central_landing.html.twig',
  3769.             [
  3770.                 'page_title' => 'Central Landing',
  3771.                 'companyNames' => $companyNames
  3772.             ]
  3773.         );
  3774.     }
  3775.     public function HummanResourceAction()
  3776.     {
  3777.         $em $this->getDoctrine()->getManager();
  3778.         $currentTime = new \Datetime();
  3779.         $currDate $currentTime->format('Y-m-d');
  3780.         $queryBuilder $em->createQueryBuilder();
  3781.         $queryBuilder->select('A.employeeId''A.entry''A.lastIn''A.lastOut''A.currentLocation','A.createdAt''E.name','E.image','D.positionName')
  3782.             ->from('ApplicationBundle\\Entity\\EmployeeAttendance''A')
  3783.             ->where('A.createdAt >=  :date')
  3784.             ->andWhere('A.createdAt <=  :date_end')
  3785.             ->leftJoin('ApplicationBundle\\Entity\\Employee''E''WITH''A.employeeId = E.employeeId')
  3786.             ->leftJoin('ApplicationBundle\\Entity\\SysDepartmentPosition''D''WITH''E.positionId = D.positionId')
  3787.             ->setParameter('date'$currDate)
  3788.             ->setParameter('date_end'$currDate ' 23:59:59')
  3789.             ->orderBy('A.createdAt''DESC'// latest records first
  3790.             ->setMaxResults(5); // limit to 5 records
  3791.         $data $queryBuilder->getQuery()->getResult();
  3792.         $formattedData array_map(function($item) {
  3793.             return [
  3794.                 'employeeId' => $item['employeeId'],
  3795.                 'entry' => $item['entry'] ? $item['entry']->format('Y-m-d H:i:s') : null,
  3796.                 'lastIn' => $item['lastIn'] ? $item['lastIn']->format('Y-m-d H:i:s') : null,
  3797.                 'lastOut' => $item['lastOut'] ? $item['lastOut']->format('Y-m-d H:i:s') : null,
  3798.                 'currentLocation' => $item['currentLocation'],
  3799.                 'createdAt' => $item['createdAt'] ? $item['createdAt']->format('Y-m-d H:i:s') : null,
  3800.                 'name' => $item['name'],
  3801.                 'image' => $item['image'],
  3802.                 'positionName' => $item['positionName'],
  3803.             ];
  3804.         }, $data);
  3805.         $totalEmployees $em->getRepository('ApplicationBundle\\Entity\\EmployeeDetails')
  3806.             ->createQueryBuilder('E')
  3807.             ->select('COUNT(E.emp_status)')
  3808.             ->where('E.emp_status = 1')
  3809.             ->getQuery()
  3810.             ->getSingleScalarResult();
  3811.         $maleCount $em->getRepository('ApplicationBundle\\Entity\\EmployeeDetails')
  3812.             ->createQueryBuilder('E')
  3813.             ->select('COUNT(E.id)')
  3814.             ->where('E.sex = 1')
  3815.             ->getQuery()
  3816.             ->getSingleScalarResult();
  3817.         $femaleCount $em->getRepository('ApplicationBundle\\Entity\\EmployeeDetails')
  3818.             ->createQueryBuilder('E')
  3819.             ->select('COUNT(E.id)')
  3820.             ->where('E.sex = 2')
  3821.             ->getQuery()
  3822.             ->getSingleScalarResult();
  3823.         $fullTime $em->getRepository('ApplicationBundle\\Entity\\EmployeeDetails')
  3824.             ->createQueryBuilder('E')
  3825.             ->select('COUNT(E.id)')
  3826.             ->where('E.empType = 1')
  3827.             ->getQuery()
  3828.             ->getSingleScalarResult();
  3829.         $partTime $em->getRepository('ApplicationBundle\\Entity\\EmployeeDetails')
  3830.             ->createQueryBuilder('E')
  3831.             ->select('COUNT(E.id)')
  3832.             ->where('E.empType = 2')
  3833.             ->getQuery()
  3834.             ->getSingleScalarResult();
  3835.         $intern $em->getRepository('ApplicationBundle\\Entity\\EmployeeDetails')
  3836.             ->createQueryBuilder('E')
  3837.             ->select('COUNT(E.id)')
  3838.             ->where('E.empType = 3')
  3839.             ->getQuery()
  3840.             ->getSingleScalarResult();
  3841.         $temporary $em->getRepository('ApplicationBundle\\Entity\\EmployeeDetails')
  3842.             ->createQueryBuilder('E')
  3843.             ->select('COUNT(E.id)')
  3844.             ->where('E.empType = 4')
  3845.             ->getQuery()
  3846.             ->getSingleScalarResult();
  3847.         $contractual $em->getRepository('ApplicationBundle\\Entity\\EmployeeDetails')
  3848.             ->createQueryBuilder('E')
  3849.             ->select('COUNT(E.id)')
  3850.             ->where('E.empType = 5')
  3851.             ->getQuery()
  3852.             ->getSingleScalarResult();
  3853.         return $this->render(
  3854.             '@Application/pages/dashboard/humanResource.html.twig',
  3855.             [
  3856.                 'page_title' => 'Human Resource Dashboard',
  3857.                 'attendanceDetails' => $formattedData,
  3858.                 'totalEmployee' => $totalEmployees,
  3859.                 'maleCount' => $maleCount,
  3860.                 'femaleCount' => $femaleCount,
  3861.                 'fullTime' => $fullTime,
  3862.                 'partTime' => $partTime,
  3863.                 'temporary' => $temporary,
  3864.                 'contractual' => $contractual,
  3865.                 'intern' => $intern,
  3866.             ]
  3867.         );
  3868.     }
  3869.     public function projectCashFlowReportAction(Request $request)
  3870.     {
  3871.         $em $this->getDoctrine()->getManager();
  3872.         $context $request->query->get('context''finance'); // 'finance' | 'projects' â€” only tweaks the active nav item
  3873.         $cashFlow = ['hasData' => false];
  3874.         try {
  3875.             $cashFlow $this->buildCompanyCashFlow($em12);
  3876.         } catch (\Throwable $e) {
  3877.             $cashFlow = ['hasData' => false'error' => $e->getMessage()];
  3878.         }
  3879.         return $this->render(
  3880.             '@Application/pages/dashboard/cash_flow_report.html.twig',
  3881.             array(
  3882.                 'page_title' => 'Cash Flow Report',
  3883.                 'cashFlow'   => $cashFlow,
  3884.                 'context'    => $context,
  3885.             )
  3886.         );
  3887.     }
  3888.     /**
  3889.      * Company cash-flow: real monthly cash inflow / outflow / net + running balance over the
  3890.      * last N months, derived from posted GL movements on the Cash &amp; Cash Equivalents head
  3891.      * subtree (marker _CACEP_ + path_tree descendants) â€” the same definition the financial
  3892.      * statements use. Base-currency amounts (amount x currency_multiply_rate). Fail-safe.
  3893.      */
  3894.     private function buildCompanyCashFlow($em$monthsBack 12)
  3895.     {
  3896.         $conn $em->getConnection();
  3897.         $cashMarker = \ApplicationBundle\Constants\AccountsConstant::CASH_AND_CASH_EQUIVALENT_PARENT;
  3898.         $result = [
  3899.             'hasData' => false,
  3900.             'labels' => [], 'inflow' => [], 'outflow' => [], 'net' => [], 'balance' => [],
  3901.             'totalInflow' => 0'totalOutflow' => 0'totalNet' => 0,
  3902.             'openingBalance' => 0'closingBalance' => 0'rows' => [],
  3903.         ];
  3904.         // 1. Resolve cash &amp; bank head ids: heads marked _CACEP_ plus their path_tree descendants.
  3905.         $marked $conn->fetchAllAssociative(
  3906.             'SELECT accounts_head_id FROM acc_accounts_head WHERE marker_hash LIKE ?',
  3907.             ['%' $cashMarker '%']
  3908.         );
  3909.         $ids = [];
  3910.         $likeParts = [];
  3911.         $params = [];
  3912.         foreach ($marked as $m) {
  3913.             $hid = (int) $m['accounts_head_id'];
  3914.             $ids[$hid] = $hid;
  3915.             $likeParts[] = 'path_tree LIKE ?';
  3916.             $params[] = '%/' $hid '/%';
  3917.         }
  3918.         if (!empty($likeParts)) {
  3919.             foreach ($conn->fetchAllAssociative('SELECT accounts_head_id FROM acc_accounts_head WHERE ' implode(' OR '$likeParts), $params) as $d) {
  3920.                 $ids[(int) $d['accounts_head_id']] = (int) $d['accounts_head_id'];
  3921.             }
  3922.         }
  3923.         $cashHeadIds array_values($ids);
  3924.         if (empty($cashHeadIds)) {
  3925.             return $result// hasData=false â†’ the page shows a friendly "no cash heads marked" notice
  3926.         }
  3927.         $inClause  implode(','array_map('intval'$cashHeadIds));
  3928.         $baseExpr  "td.amount * COALESCE(NULLIF(td.currency_multiply_rate, ''), 1)";
  3929.         $drCond    "(LOWER(td.position) LIKE 'dr%' OR LOWER(td.position) = 'debit')";
  3930.         $start = new \DateTime('first day of this month 00:00:00');
  3931.         $start->modify('-' . ($monthsBack 1) . ' months');
  3932.         $startStr $start->format('Y-m-d 00:00:00');
  3933.         // Opening cash balance (Dr - Cr) before the window.
  3934.         $openRow $conn->fetchAssociative(
  3935.             "SELECT SUM(CASE WHEN $drCond THEN $baseExpr ELSE -($baseExpr) END) bal
  3936.              FROM acc_transaction_details td
  3937.              JOIN acc_transactions t ON t.transaction_id = td.transaction_id
  3938.              WHERE td.accounts_head_id IN ($inClause) AND td.ledger_hit = 1 AND t.transaction_date < ?",
  3939.             [$startStr]
  3940.         );
  3941.         $opening = (float) ($openRow['bal'] ?? 0);
  3942.         // Monthly movements inside the window.
  3943.         $rows $conn->fetchAllAssociative(
  3944.             "SELECT DATE_FORMAT(t.transaction_date, '%Y-%m') ym,
  3945.                     SUM(CASE WHEN $drCond THEN $baseExpr ELSE 0 END) inflow,
  3946.                     SUM(CASE WHEN NOT $drCond THEN $baseExpr ELSE 0 END) outflow
  3947.              FROM acc_transaction_details td
  3948.              JOIN acc_transactions t ON t.transaction_id = td.transaction_id
  3949.              WHERE td.accounts_head_id IN ($inClause) AND td.ledger_hit = 1 AND t.transaction_date >= ?
  3950.              GROUP BY ym",
  3951.             [$startStr]
  3952.         );
  3953.         $byMonth = [];
  3954.         foreach ($rows as $r) {
  3955.             $byMonth[$r['ym']] = ['in' => (float) $r['inflow'], 'out' => (float) $r['outflow']];
  3956.         }
  3957.         $running $opening;
  3958.         $cursor = clone $start;
  3959.         for ($i 0$i $monthsBack$i++) {
  3960.             $ym $cursor->format('Y-m');
  3961.             $in  = isset($byMonth[$ym]) ? $byMonth[$ym]['in']  : 0.0;
  3962.             $out = isset($byMonth[$ym]) ? $byMonth[$ym]['out'] : 0.0;
  3963.             $net $in $out;
  3964.             $running += $net;
  3965.             $result['labels'][]  = $cursor->format('M Y');
  3966.             $result['inflow'][]  = round($in2);
  3967.             $result['outflow'][] = round($out2);
  3968.             $result['net'][]     = round($net2);
  3969.             $result['balance'][] = round($running2);
  3970.             $result['rows'][]    = ['label' => $cursor->format('M Y'), 'inflow' => round($in2), 'outflow' => round($out2), 'net' => round($net2), 'balance' => round($running2)];
  3971.             $result['totalInflow']  += $in;
  3972.             $result['totalOutflow'] += $out;
  3973.             $cursor->modify('+1 month');
  3974.         }
  3975.         $result['hasData']        = true;
  3976.         $result['openingBalance'] = round($opening2);
  3977.         $result['closingBalance'] = round($running2);
  3978.         $result['totalNet']       = round($result['totalInflow'] - $result['totalOutflow'], 2);
  3979.         $result['totalInflow']    = round($result['totalInflow'], 2);
  3980.         $result['totalOutflow']   = round($result['totalOutflow'], 2);
  3981.         return $result;
  3982.     }
  3983.     public function PerformanceReviewDashboardAction()
  3984.     {
  3985.         return $this->render(
  3986.             '@Application/pages/dashboard/performance_review_dashboard.html.twig',
  3987.             array(
  3988.                 'page_title' => 'Performance Review Dashboard'
  3989.             )
  3990.         );
  3991.     }
  3992.     public function RecruitmentDashboardAction(Request $request)
  3993.     {
  3994.         $em $this->getDoctrine()->getManager();
  3995.         $em_goc $this->getDoctrine()->getManager('company_group');
  3996.         $companyId $this->getLoggedUserCompanyId($request);
  3997.         $company_data Company::getCompanyData($em$companyId);
  3998.         // 1. Total Job Posts
  3999.         $totalJobPosts $em->getRepository('ApplicationBundle\\Entity\\JobRecruitment')
  4000.             ->createQueryBuilder('j')
  4001.             ->select('COUNT(j.jobRecruitmentId)')
  4002.             ->where('j.approved = 1')
  4003.             ->getQuery()
  4004.             ->getSingleScalarResult();
  4005.         // 2. Active Job Posts
  4006.         $activeJobPosts $em->getRepository('ApplicationBundle\\Entity\\JobRecruitment')
  4007.             ->createQueryBuilder('j')
  4008.             ->select('COUNT(j.jobRecruitmentId)')
  4009.             ->where('j.approved = 1')
  4010.             ->andWhere('j.jobOpeningStatus = 2'// Assuming 2 is Active
  4011.             ->getQuery()
  4012.             ->getSingleScalarResult();
  4013.         // 3. Total Applicants
  4014.         $totalApplicants $em_goc->getRepository("CompanyGroupBundle\\Entity\\EntityApplicantApplicationList")
  4015.             ->createQueryBuilder('a')
  4016.             ->select('COUNT(a.id)')
  4017.             ->where('a.CompanyId = :companyId')
  4018.             ->andWhere('a.appId = :appId')
  4019.             ->setParameter('companyId'$companyId)
  4020.             ->setParameter('appId'$company_data->getAppId())
  4021.             ->getQuery()
  4022.             ->getSingleScalarResult();
  4023.         // 4. Simple recent activity for dashboard
  4024.         $recentJobs $em->getRepository('ApplicationBundle\\Entity\\JobRecruitment')
  4025.             ->findBy(['approved' => 1], ['createdAt' => 'DESC'], 5);
  4026.         // 5. Jobs with applicant counts
  4027.         $jobsWithApplicantCount $em->getRepository('ApplicationBundle\\Entity\\JobRecruitment')
  4028.             ->createQueryBuilder('j')
  4029.             ->select('j.jobRecruitmentId''j.title''j.applicationClosingDate''j.jobOpeningStatus')
  4030.             ->where('j.approved = 1')
  4031.             ->orderBy('j.createdAt''DESC')
  4032.             ->setMaxResults(8)
  4033.             ->getQuery()
  4034.             ->getResult();
  4035.         foreach ($jobsWithApplicantCount as &$job) {
  4036.             $count $em_goc->getRepository("CompanyGroupBundle\\Entity\\EntityApplicantApplicationList")
  4037.                 ->createQueryBuilder('a')
  4038.                 ->select('COUNT(a.id)')
  4039.                 ->where('a.jobPostId = :jobId')
  4040.                 ->setParameter('jobId'$job['jobRecruitmentId'])
  4041.                 ->getQuery()
  4042.                 ->getSingleScalarResult();
  4043.             $job['applicantCount'] = $count;
  4044.         }
  4045.         return $this->render(
  4046.             '@Application/pages/dashboard/recruitment_dashboard.html.twig',
  4047.             array(
  4048.                 'page_title' => 'Recruitment Dashboard',
  4049.                 'totalJobPosts' => $totalJobPosts,
  4050.                 'activeJobPosts' => $activeJobPosts,
  4051.                 'totalApplicants' => $totalApplicants,
  4052.                 'recentJobs' => $recentJobs,
  4053.                 'jobsWithApplicantCount' => $jobsWithApplicantCount,
  4054.                 'jobOpeningStatusArr' => HumanResourceConstant::$jobOpeningStatus
  4055.             )
  4056.         );
  4057.     }
  4058.     public function TalentManagementDashboardAction()
  4059.     {
  4060.         return $this->render(
  4061.             '@Application/pages/dashboard/talent_management_dashboard.html.twig',
  4062.             array(
  4063.                 'page_title' => 'Talent Management Dashboard'
  4064.             )
  4065.         );
  4066.     }
  4067.     public function CreateCompanyAction(Request $request)
  4068.     {
  4069.         $systemType $this->container->hasParameter('system_type') ? $this->container->getParameter('system_type') : '_ERP_';
  4070.         $appId $request->get('app_id'0);
  4071.         $post $request;
  4072.         $session $request->getSession();
  4073.         if ($request->isMethod('POST')) {
  4074.             if ($systemType == '_CENTRAL_') {
  4075.                 $em_goc $this->getDoctrine()->getManager('company_group');
  4076.                 $em_goc->getConnection()->connect();
  4077.                 $connected $em_goc->getConnection()->isConnected();
  4078.                 $gocDataList = [];
  4079.                 if ($connected) {
  4080.                     $goc null;
  4081.                     $serverList MiscActions::getServerListById(                     $this->container->getParameter('database_user'),                     $this->container->getParameter('database_password'),                     $this->container->hasParameter('server_access_list') ?$this->container->getParameter('server_access_list') :[]                 );
  4082.                     $companyGroupHash $post->get('company_short_code''');
  4083.                     $defaultUsageDate = new \DateTime();
  4084.                     $defaultUsageDate->modify('+1 year');
  4085.                     $usageValidUpto = new \DateTime($post->get('usage_valid_upto_dt_str'$defaultUsageDate->format('Y-m-d')));
  4086.                     $companyGroupServerId $post->get('server_id'1);
  4087.                     $companyGroupServerAddress $serverList[$companyGroupServerId]['absoluteUrl'];
  4088.                     $companyGroupServerPort $serverList[$companyGroupServerId]['port'];
  4089.                     $companyGroupServerHash $serverList[$companyGroupServerId]['serverMarker'];
  4090.                     //                $dbUser=
  4091.                     if ($appId != 0)
  4092.                         $goc $this->getDoctrine()->getManager('company_group')
  4093.                             ->getRepository("CompanyGroupBundle\\Entity\\CompanyGroup")
  4094.                             ->findOneBy(array(
  4095.                                 'appId' => $appId
  4096.                             ));
  4097.                     if (!$goc)
  4098.                         $goc = new CompanyGroup();
  4099.                     if ($appId == 0) {
  4100.                         $biggestAppIdCg $this->getDoctrine()->getManager('company_group')
  4101.                             ->getRepository("CompanyGroupBundle\\Entity\\CompanyGroup")
  4102.                             ->findOneBy(array( //                            'appId' => $appId
  4103.                             ), array(
  4104.                                 'appId' => 'desc'
  4105.                             ));
  4106.                         if ($biggestAppIdCg)
  4107.                             $appId $biggestAppIdCg->getAppId();
  4108.                     }
  4109.                     $goc->setName($post->get('company_name'));
  4110.                     $goc->setCompanyGroupHash($companyGroupHash);
  4111.                     $goc->setAppId($appId);
  4112.                     $goc->setActive(1);
  4113.                     $goc->setAddress($post->get('address'));
  4114.                     $goc->setShippingAddress($post->get('s_address'));
  4115.                     $goc->setBillingAddress($post->get('b_address'));
  4116.                     $goc->setMotto($post->get('motto'));
  4117.                     $goc->setInitiateFlag($post->get('initiate_flag'3));
  4118.                     $goc->setInvoiceFooter($post->get('i_footer'));
  4119.                     $goc->setGeneralFooter($post->get('g_footer'));
  4120.                     $goc->setCompanyReg($post->get('company_reg'''));
  4121.                     $goc->setCompanyTin($post->get('company_tin'''));
  4122.                     $goc->setCompanyBin($post->get('company_bin'''));
  4123.                     $goc->setCompanyTl($post->get('company_tl'''));
  4124.                     $goc->setCompanyType($post->get('company_type'''));
  4125.                     $goc->setCurrentSubscriptionPackageId($post->get('package'1));
  4126.                     $goc->setUsageValidUptoDate($usageValidUpto);
  4127.                     $goc->setUsageValidUptoDateTs($usageValidUpto->format('U'));
  4128.                     //                $goc->setCu($post->get('package', ''));
  4129.                     $goc->setAdminUserAllowed($post->get('number_of_admin_user'1));
  4130.                     $goc->setUserAllowed($post->get('number_of_user'2));
  4131.                     $goc->setSubscriptionMonth($post->get('subscription_month'1));
  4132.                     $goc->setCompanyDescription($post->get('company_description'''));
  4133.                     $goc->setDbUser($post->get('db_user'));
  4134.                     $goc->setDbPass($post->get('db_pass'));
  4135.                     $goc->setDbHost($post->get('db_host'));
  4136.                     $goc->setOwnerId($session->get(UserConstants::USER_ID));
  4137.                     $goc->setCompanyGroupServerId($companyGroupServerId);
  4138.                     $goc->setCompanyGroupServerAddress($companyGroupServerAddress);
  4139.                     $goc->setCompanyGroupServerPort($companyGroupServerPort);
  4140.                     $goc->setCompanyGroupServerHash($companyGroupServerHash);
  4141.                     foreach ($request->files as $uploadedFile) {
  4142.                         if ($uploadedFile != null) {
  4143.                             $fileName 'company_image' $appId '.' $uploadedFile->guessExtension();
  4144.                             $path $fileName;
  4145.                             $upl_dir $this->container->getParameter('kernel.root_dir') . '/../web/uploads/CompanyImage/';
  4146.                             if ($goc->getImage() != null && $goc->getImage() != '' && file_exists($this->container->getParameter('kernel.root_dir') . '/../web' $goc->getImage())) {
  4147.                                 unlink($this->container->getParameter('kernel.root_dir') . '/../web' $goc->getImage());
  4148.                             }
  4149.                             if (!file_exists($upl_dir)) {
  4150.                                 mkdir($upl_dir0777true);
  4151.                             }
  4152.                             $file $uploadedFile->move($upl_dir$path);
  4153.                             if ($path != "")
  4154.                                 $goc->setImage('/uploads/CompanyImage/' $path);
  4155.                         }
  4156.                     }
  4157.                     $em_goc->persist($goc);
  4158.                     $em_goc->flush();
  4159.                     $goc->setDbName('cg_' $appId '_' $companyGroupHash);
  4160.                     $goc->setDbUser($serverList[$companyGroupServerId]['dbUser']);
  4161.                     $goc->setDbPass($serverList[$companyGroupServerId]['dbPass']);
  4162.                     $goc->setDbHost('localhost');
  4163.                     $em_goc->flush();
  4164.                     $centralUser $this->getDoctrine()->getManager('company_group')
  4165.                         ->getRepository("CompanyGroupBundle\\Entity\\EntityApplicantDetails")
  4166.                         ->findOneBy(array(
  4167.                             'applicantId' => $session->get(UserConstants::USER_ID0)
  4168.                         ));
  4169.                     if ($centralUser) {
  4170.                         $userAppIds json_decode($centralUser->getUserAppIds(), true);
  4171.                         $userTypesByAppIds json_decode($centralUser->getUserTypesByAppIds(), true);
  4172.                         if ($userAppIds == null$userAppIds = [];
  4173.                         if ($userTypesByAppIds == null$userTypesByAppIds = [];
  4174.                         $userAppIds array_merge($userAppIdsarray_diff([$appId], $userAppIds));
  4175.                         if (!isset($userTypesByAppIds[$appId])) {
  4176.                             $userTypesByAppIds[$appId] = [];
  4177.                         }
  4178.                         $userTypesByAppIds[$appId] = array_merge($userTypesByAppIds[$appId], array_diff([UserConstants::USER_TYPE_SYSTEM], $userTypesByAppIds[$appId]));
  4179.                         $centralUser->setUserAppIds(json_encode($userAppIds));
  4180.                         $centralUser->setUserTypesByAppIds(json_encode($userTypesByAppIds));
  4181.                         $em_goc->flush();
  4182.                     }
  4183.                     $accessList $session->get('userAccessList', []);
  4184.                     $d = array(
  4185.                         'userType' => UserConstants::USER_TYPE_SYSTEM,
  4186.                         'globalId' => $session->get(UserConstants::USER_ID0),
  4187.                         'serverId' => $companyGroupServerId,
  4188.                         'serverUrl' => $companyGroupServerAddress,
  4189.                         'serverPort' => $companyGroupServerPort,
  4190.                         'systemType' => '_ERP_',
  4191.                         'companyId' => 1,
  4192.                         'appId' => $appId,
  4193.                         'companyLogoUrl' => $goc->getImage(),
  4194.                         'companyName' => $goc->getName(),
  4195.                         'authenticationStr' => $this->get('url_encryptor')->encrypt(
  4196.                             json_encode(
  4197.                                 array(
  4198.                                     'globalId' => $session->get(UserConstants::USER_ID0),
  4199.                                     'appId' => $appId,
  4200.                                     'authenticate' => 1,
  4201.                                     'userType' => UserConstants::USER_TYPE_SYSTEM
  4202.                                 )
  4203.                             )
  4204.                         ),
  4205.                         'userCompanyList' => []
  4206.                     );
  4207.                     $accessList[] = $d;
  4208. //                    MiscActions::UpdateCompanyListInSession($em_goc, $centralUser->getApplicantId(), 1, 1, 1, $d);
  4209.                     //temporary solution
  4210.                     MiscActions::UpdateCompanyListInSession($em_goc$session->get(UserConstants::USER_ID), 111$d);
  4211.                     $session->set('userAccessList'$accessList);
  4212.                 }
  4213.                 return new JsonResponse(array(
  4214.                     'success' => true,
  4215.                     "message" => "Company Created Successfully",
  4216.                     'user_access_data' => $d,
  4217.                     'app_id' => $appId
  4218.                 ));
  4219.             }
  4220.         }
  4221.         return $this->render('@HoneybeeWeb/pages/create_company.html.twig', array(
  4222.             'page_title' => 'Company',
  4223.             'serverList' => GeneralConstant::$serverListById
  4224.         ));
  4225.     }
  4226.     public function checkBinTinAction(Request $request)
  4227.     {
  4228.         $em_goc $this->getDoctrine()->getManager('company_group');
  4229.         $type  $request->request->get('type');
  4230.         $value trim($request->request->get('value'));
  4231.         $repo $em_goc->getRepository("CompanyGroupBundle\\Entity\\CompanyGroup");
  4232.         if ($type === 'tin') {
  4233.             $company $repo->findOneBy(array(
  4234.                 'company_tin' => $value
  4235.             ));
  4236.         } elseif ($type === 'bin') {
  4237.             $company $repo->findOneBy(array(
  4238.                 'company_bin' => $value
  4239.             ));
  4240.         } elseif ($type === 'reg') {
  4241.             $company $repo->findOneBy(array(
  4242.                 'company_reg' => $value
  4243.             ));
  4244.         } else {
  4245.             return new JsonResponse(['exists' => false]);
  4246.         }
  4247.         return new JsonResponse([
  4248.             'exists' => $company true false
  4249.         ]);
  4250.     }
  4251.     public function createTicketAction(Request $request)
  4252.     {
  4253.         $em_goc $this->getDoctrine()->getManager('company_group');
  4254.         if ($request->isMethod('POST')) {
  4255.             $ticket = new EntityTicket();
  4256.             $ticket->setTitle($request->request->get('title'0));
  4257.             $ticket->setEmail($request->request->get('email'));
  4258.             $ticket->setTicketBody($request->request->get('ticketBody'));
  4259.             $em_goc->persist($ticket);
  4260.             $em_goc->flush();
  4261.         }
  4262.         return new JsonResponse(array(
  4263.             "success" => 'true',
  4264.             "message" => "Ticket Created Successfully",
  4265.         ));
  4266.     }
  4267.     public function GetSessionDataForAppAction(
  4268.         Request $request,
  4269.                 $remoteVerify 0,
  4270.                 $version 'latest',
  4271.                 $identifier '_default_',
  4272.                 $refRoute '',
  4273.                 $apiKey '_ignore_'
  4274.     )
  4275.     {
  4276.         $message "";
  4277.         $gocList = [];
  4278.         $session $request->getSession();
  4279.         if ($request->request->has('token')) {
  4280.             $em_goc $this->getDoctrine()->getManager('company_group');
  4281.             $to_set_session_data MiscActions::GetSessionDataFromToken($em_goc$request->request->get('token'))['sessionData'];
  4282.             if ($to_set_session_data != null) {
  4283.                 foreach ($to_set_session_data as $k => $d) {
  4284.                     //check if mobile
  4285.                     $session->set($k$d);
  4286.                 }
  4287.             }
  4288.         }
  4289.         if ($request->request->has('sessionData')) {
  4290.             $to_set_session_data $request->request->get('sessionData');
  4291.             foreach ($to_set_session_data as $k => $d) {
  4292.                 //check if mobile
  4293.                 $session->set($k$d);
  4294.             }
  4295.         }
  4296.         if ($version !== 'latest') {
  4297.             $session_data = array(
  4298.                 'oAuthToken' => $session->get('oAuthToken'),
  4299.                 'locale' => $session->get('locale'),
  4300.                 'firebaseToken' => $session->get('firebaseToken'),
  4301.                 'token' => $session->get('token'),
  4302.                 UserConstants::USER_EMPLOYEE_ID => $session->get(UserConstants::USER_EMPLOYEE_ID),
  4303.                 UserConstants::USER_ID => $session->get(UserConstants::USER_ID),
  4304.                 UserConstants::LAST_SETTINGS_UPDATED_TS => $session->get(UserConstants::LAST_SETTINGS_UPDATED_TS),
  4305.                 UserConstants::USER_LOGIN_ID => $session->get(UserConstants::USER_LOGIN_ID),
  4306.                 UserConstants::USER_EMAIL => $session->get(UserConstants::USER_EMAIL),
  4307.                 UserConstants::USER_TYPE => $session->get(UserConstants::USER_TYPE),
  4308.                 UserConstants::USER_IMAGE => $session->get(UserConstants::USER_IMAGE),
  4309.                 UserConstants::USER_DEFAULT_ROUTE => $session->get(UserConstants::USER_DEFAULT_ROUTE),
  4310.                 UserConstants::USER_NAME => $session->get(UserConstants::USER_NAME),
  4311.                 UserConstants::USER_COMPANY_ID => $session->get(UserConstants::USER_COMPANY_ID),
  4312.                 UserConstants::USER_COMPANY_ID_LIST => $session->get(UserConstants::USER_COMPANY_ID_LIST),
  4313.                 UserConstants::USER_COMPANY_NAME_LIST => $session->get(UserConstants::USER_COMPANY_NAME_LIST),
  4314.                 UserConstants::USER_COMPANY_IMAGE_LIST => $session->get(UserConstants::USER_COMPANY_IMAGE_LIST),
  4315.                 UserConstants::USER_APP_ID => $session->get(UserConstants::USER_APP_ID),
  4316.                 UserConstants::USER_POSITION_LIST => $session->get(UserConstants::USER_POSITION_LIST),
  4317.                 UserConstants::USER_CURRENT_POSITION => $session->get(UserConstants::USER_CURRENT_POSITION),
  4318.                 UserConstants::ALL_MODULE_ACCESS_FLAG => $session->get(UserConstants::ALL_MODULE_ACCESS_FLAG),
  4319.                 UserConstants::USER_GOC_ID => $session->get(UserConstants::USER_GOC_ID),
  4320.                 UserConstants::USER_NOTIFICATION_ENABLED => GeneralConstant::NOTIFICATION_ENABLED == ? ($this->getParameter('notification_enabled') == 0) : 0,
  4321.                 UserConstants::USER_NOTIFICATION_SERVER => $this->getParameter('notification_server'),
  4322.                 UserConstants::PRODUCT_NAME_DISPLAY_TYPE => $session->get(UserConstants::PRODUCT_NAME_DISPLAY_TYPE),
  4323.                 UserConstants::APPLICATION_SECRET => $session->get(UserConstants::APPLICATION_SECRET),
  4324.                 //new addition
  4325.                 'appIdList' => $session->get('appIdList'),
  4326.                 'branchIdList' => $session->get('branchIdList'null),
  4327.                 'branchId' => $session->get('branchId'null),
  4328.                 'companyIdListByAppId' => $session->get('companyIdListByAppId'),
  4329.                 'companyNameListByAppId' => $session->get('companyNameListByAppId'),
  4330.                 'companyImageListByAppId' => $session->get('companyImageListByAppId'),
  4331.                 'userAccessList' => $session->get('userAccessList'),
  4332.                 'csToken' => $session->get('csToken'),
  4333.             );
  4334.         } else {
  4335.             $session_data = array(
  4336.                 'oAuthToken' => $session->get('oAuthToken'),
  4337.                 'locale' => $session->get('locale'),
  4338.                 'firebaseToken' => $session->get('firebaseToken'),
  4339.                 'token' => $session->get('token'),
  4340.                 UserConstants::USER_EMPLOYEE_ID => $session->get(UserConstants::USER_EMPLOYEE_ID),
  4341.                 UserConstants::USER_ID => $session->get(UserConstants::USER_ID),
  4342.                 UserConstants::LAST_SETTINGS_UPDATED_TS => $session->get(UserConstants::LAST_SETTINGS_UPDATED_TS),
  4343.                 UserConstants::USER_LOGIN_ID => $session->get(UserConstants::USER_LOGIN_ID),
  4344.                 UserConstants::USER_EMAIL => $session->get(UserConstants::USER_EMAIL),
  4345.                 UserConstants::USER_TYPE => $session->get(UserConstants::USER_TYPE),
  4346.                 UserConstants::USER_IMAGE => $session->get(UserConstants::USER_IMAGE),
  4347.                 UserConstants::USER_DEFAULT_ROUTE => $session->get(UserConstants::USER_DEFAULT_ROUTE),
  4348.                 UserConstants::USER_NAME => $session->get(UserConstants::USER_NAME),
  4349.                 UserConstants::USER_COMPANY_ID => $session->get(UserConstants::USER_COMPANY_ID),
  4350.                 UserConstants::USER_COMPANY_ID_LIST => $session->get(UserConstants::USER_COMPANY_ID_LIST),
  4351.                 UserConstants::USER_COMPANY_NAME_LIST => $session->get(UserConstants::USER_COMPANY_NAME_LIST),
  4352.                 UserConstants::USER_COMPANY_IMAGE_LIST => $session->get(UserConstants::USER_COMPANY_IMAGE_LIST),
  4353.                 UserConstants::USER_APP_ID => $session->get(UserConstants::USER_APP_ID),
  4354.                 UserConstants::USER_POSITION_LIST => $session->get(UserConstants::USER_POSITION_LIST),
  4355.                 UserConstants::USER_CURRENT_POSITION => $session->get(UserConstants::USER_CURRENT_POSITION),
  4356.                 UserConstants::ALL_MODULE_ACCESS_FLAG => $session->get(UserConstants::ALL_MODULE_ACCESS_FLAG),
  4357.                 UserConstants::USER_GOC_ID => $session->get(UserConstants::USER_GOC_ID),
  4358.                 UserConstants::USER_NOTIFICATION_ENABLED => GeneralConstant::NOTIFICATION_ENABLED == ? ($this->getParameter('notification_enabled') == 0) : 0,
  4359.                 UserConstants::USER_NOTIFICATION_SERVER => $this->getParameter('notification_server'),
  4360.                 UserConstants::PRODUCT_NAME_DISPLAY_TYPE => $session->get(UserConstants::PRODUCT_NAME_DISPLAY_TYPE),
  4361.                 UserConstants::APPLICATION_SECRET => $session->get(UserConstants::APPLICATION_SECRET),
  4362.                 //new addition
  4363.                 'appIdList' => $session->get('appIdList'),
  4364.                 'branchIdList' => $session->get('branchIdList'null),
  4365.                 'branchId' => $session->get('branchId'null),
  4366.                 'companyIdListByAppId' => $session->get('companyIdListByAppId'),
  4367.                 'companyNameListByAppId' => $session->get('companyNameListByAppId'),
  4368.                 'companyImageListByAppId' => $session->get('companyImageListByAppId'),
  4369.                 'userAccessList' => $session->get('userAccessList'),
  4370.                 'csToken' => $session->get('csToken'),
  4371.             );
  4372.         }
  4373.         $response = new JsonResponse(array(
  4374.             "success" => empty($session->get(UserConstants::USER_ID)) ? false true,
  4375.             //            'session'=>$request->getSession(),
  4376.             'session_data' => $session_data,
  4377.             //            'session2'=>$_SESSION,
  4378.         ));
  4379.         $response->headers->set('Access-Control-Allow-Origin''*, null');
  4380.         $response->headers->set('Access-Control-Allow-Methods''POST');
  4381.         //        $response->setCallback('FUNCTION_CALLBACK_NAME');
  4382.         return $response;
  4383.     }
  4384.     public function EmployeeAddUsingQrCodeCentralAction(Request $request)
  4385.     {
  4386.         $session $request->getSession();
  4387.         if ($request->isMethod('post')) {
  4388.             $em_goc $this->getDoctrine()->getManager('company_group');
  4389.             $entityApplicant $em_goc->getRepository("CompanyGroupBundle\\Entity\\EntityApplicantDetails")
  4390.                 ->findOneBy(
  4391.                     array(
  4392.                         'applicantId' => $request->request->get('userId'),
  4393.                     )
  4394.                 );
  4395.             $app $em_goc->getRepository("CompanyGroupBundle\\Entity\\CompanyGroup")
  4396.                 ->findOneBy(
  4397.                     array(
  4398.                         'appId' => $request->request->get('appId'),
  4399.                     )
  4400.                 );
  4401.             $userType $request->request->get('userType');
  4402.             $currAccessData json_decode($entityApplicant->getUserTypesByAppIds(), true);
  4403.             if ($currAccessData == null$currAccessData = [];
  4404.             if (!isset($currAccessData[$request->request->get('appId')]))
  4405.                 $currAccessData[$request->request->get('appId')] = [];
  4406.             $currAccessData[$request->request->get('appId')] = array_merge($currAccessData[$request->request->get('appId')], array_diff([$request->request->get('userType'$userType)], $currAccessData[$request->request->get('appId')]));
  4407.             $entityApplicant->setUserTypesByAppIds(json_encode($currAccessData));
  4408.             $em_goc->flush();
  4409.             $postData = [];
  4410.             $postData['globalId'] = $entityApplicant->getApplicantId();
  4411.             $postData['username'] = $entityApplicant->getUsername();
  4412.             $postData['email'] = $entityApplicant->getEmail();
  4413.             $postData['firstname'] = $entityApplicant->getFirstname();
  4414.             $postData['lastname'] = $entityApplicant->getLastname();
  4415.             $postData['appId'] = $request->request->get('appId');
  4416.             $postData['companyId'] = $request->request->get('companyId');
  4417.             $postData['userType'] = $userType;
  4418.             $urlToCall $app->getCompanyGroupServerAddress() . '/add_employee_by_qr_erp';
  4419.             $userFiles $postData;
  4420.             $curl curl_init();
  4421.             curl_setopt_array($curl, array(
  4422.                 CURLOPT_RETURNTRANSFER => 1,
  4423.                 CURLOPT_POST => 1,
  4424.                 CURLOPT_URL => $urlToCall,
  4425.                 CURLOPT_CONNECTTIMEOUT => 10,
  4426.                 CURLOPT_SSL_VERIFYPEER => false,
  4427.                 CURLOPT_SSL_VERIFYHOST => false,
  4428.                 CURLOPT_HTTPHEADER => array( //              "Accept: multipart/form-data",
  4429.                 ),
  4430.                 //                            ),
  4431.                 CURLOPT_POSTFIELDS => $userFiles
  4432.             ));
  4433.             $retData curl_exec($curl);
  4434.             $errData curl_error($curl);
  4435.             curl_close($curl);
  4436.             if ($errData) {
  4437. //                $returnData['message']='';
  4438.             } else {
  4439.                 $retDataObj json_decode($retDatatrue);
  4440.                 if ($retDataObj['status'] == 'success') {
  4441.                     $newAccess = [
  4442.                         'userType' => 1,
  4443.                         'userTypeName' => 'Admin',
  4444.                         'globalId' => $entityApplicant->getApplicantId(),
  4445.                         'serverId' => $app->getCompanyGroupServerId(),
  4446.                         'serverUrl' => $app->getCompanyGroupServerAddress(),
  4447.                         'serverPort' => $app->getCompanyGroupServerPort(),
  4448.                         'systemType' => '_ERP_',
  4449.                         'companyId' => 1,
  4450.                         'appId' => $app->getAppId(),
  4451.                         'companyLogoUrl' => '/uploads/CompanyImage/company_image' $request->request->get('appId') . '.png',
  4452.                         'companyName' => $app->getName(),
  4453.                         'authenticationStr' => $this->get('url_encryptor')->encrypt(json_encode(
  4454.                                 array(
  4455.                                     'globalId' => $entityApplicant->getApplicantId(),
  4456.                                     'appId' => $app->getAppId(),
  4457.                                     'authenticate' => 1,
  4458.                                     'userType' => $userType,
  4459.                                     'userTypeName' => UserConstants::$userTypeName[$userType]
  4460.                                 )
  4461.                             )
  4462.                         ),
  4463.                         'userCompanyList' => [],
  4464.                     ];
  4465. //            $token = $session->get('token');
  4466. //            $em_goc = $this->getDoctrine()->getManager('company_group');
  4467.                     $to_set_session_data MiscActions::GetSessionDataFromToken($em_goc$session->get(UserConstants::USER_TOKEN''))['sessionData'];
  4468.                     $currentUserAccessListInSession $to_set_session_data['userAccessList'];
  4469.                     $isAlreadyJoined false;
  4470.                     foreach ($currentUserAccessListInSession as $acc) {
  4471.                         if (isset($acc['appId']) && $acc['appId'] == $request->request->get('appId')) {
  4472.                             $isAlreadyJoined true;
  4473.                             break;
  4474.                         }
  4475.                     }
  4476. //                    if(isset($currentUserAccessListInSession[$request->request->get('appId')]))
  4477. //                        $isAlreadyJoined=true;
  4478.                     if ($isAlreadyJoined) {
  4479.                         return new JsonResponse([
  4480.                             'status' => 'false',
  4481.                             'message' => 'Already joined.',
  4482.                             'currentUserAccessListInSession'  => $currentUserAccessListInSession
  4483.                         ]);
  4484.                     }else{
  4485.                         $currentUserAccessListInSession[] = $newAccess;
  4486.                         $session->set('userAccessList'$currentUserAccessListInSession);
  4487.                         $to_set_session_data['userAccessList'] = $currentUserAccessListInSession;
  4488.                         $updatedToken MiscActions::CreateTokenFromSessionData($em_goc,
  4489.                             $to_set_session_data,
  4490.                             1,
  4491.                             1,
  4492.                             11
  4493.                         );
  4494.                         return new JsonResponse([
  4495.                             'status' => 'success',
  4496.                             'message' => 'User successfully added to company.',
  4497.                             'currentUserAccessListInSession'  => $currentUserAccessListInSession
  4498.                         ]);
  4499.                     }
  4500.                 }
  4501.             }
  4502. //            MiscActions::UpdateCompanyListInSession($em_goc, $entityApplicant->getApplicantId(), 1, 1, 1, $newAccess);
  4503.         } else {
  4504.             $company $request->get('company');
  4505.             return new JsonResponse(array(
  4506.                 'status' => 'error',
  4507.                 'message' => 'Something went wrong while onboarding.'
  4508.             ));
  4509.         }
  4510.         return new JsonResponse(array(
  4511.             'status' => 'error',
  4512.             'message' => 'Something went wrong while onboarding.'
  4513.         ));
  4514.     }
  4515.     public function EmployeeAddUsingQrCodeAction(Request $request)
  4516.     {
  4517.         $post $request;
  4518.         $em $this->getDoctrine()->getManager('company_group');
  4519.         $appid $request->query->get('appid'$request->request->get('appid'null));
  4520.         $session $request->getSession();
  4521.         $CurrentRoute $request->attributes->get('_route');
  4522.         $systemType $this->container->hasParameter('system_type') ? $this->container->getParameter('system_type') : '_ERP_';
  4523.         if ($request->isMethod('POST')) {
  4524.             $userId $request->request->get('userId'null);
  4525.             if ($userId === null) {
  4526.                 $companyId $request->request->get('company',1);
  4527.                 $email $request->request->get('email');
  4528.                 $qrImage $request->files->get('qr_image');
  4529.                 if (!$email) {
  4530.                     return new JsonResponse(['status' => 'error''message' => 'Invalid request'], 400);
  4531.                 }
  4532.                 if ($qrImage) {
  4533.                     $uploadsDir $this->getParameter('kernel.project_dir') . '/public/uploads/';
  4534.                     $fileName 'qr_' $companyId '_' time() . '.png';
  4535.                     $qrImage->move($uploadsDir$fileName);
  4536.                     $qrImagePath $uploadsDir $fileName;
  4537.                     $bodyTemplate '@Application/email/user/applicant_confirm.html.twig';
  4538.                     $bodyData = [
  4539.                         'name' => $email,
  4540.                         'companyData' => $companyId,
  4541.                         'companyName' => $request->request->get('company'),
  4542.                         'userType' => 2,
  4543.                         'appId' => $appid,
  4544.                         //                        'qr_code_url' => '/uploads/' . $fileName
  4545.                     ];
  4546.                     $userAccessList $session->get('userAccessList', []);
  4547.                     $companyName array_map(function ($company) {
  4548.                         return $company['companyName'];
  4549.                     }, $userAccessList);
  4550.                     $new_mail $this->get('mail_module');
  4551.                     $new_mail->sendMyMail([
  4552.                         'senderHash' => '_CUSTOM_',
  4553.                         'forwardToMailAddress' => $email,
  4554.                         'fromAddress' => 'accounts@ourhoneybee.eu',
  4555.                         'userName' => 'accounts@ourhoneybee.eu',
  4556.                         'password' => \ApplicationBundle\Helper\MailerConfig::buddybeePassword(),
  4557.                         'smtpServer' => \ApplicationBundle\Helper\MailerConfig::host(),
  4558.                         'smtpPort' => \ApplicationBundle\Helper\MailerConfig::port(),
  4559.                         'subject' => 'User Registration on HoneyBee Ecosystem under Entity ',
  4560.                         'toAddress' => $email,
  4561.                         'mailTemplate' => $bodyTemplate,
  4562.                         'templateData' => $bodyData,
  4563.                         'companyId' => $companyId,
  4564.                     ]);
  4565.                     return $this->render(
  4566.                         '@Application/pages/dashboard/index_central_landing.html.twig',
  4567.                         [
  4568.                             'page_title' => 'Central Landing',
  4569.                             'companyNames' => $companyName
  4570.                         ]
  4571.                     );
  4572.                 } else {
  4573.                     $userAccessList $session->get('userAccessList', []);
  4574.                     $companyName array_map(function ($company) {
  4575.                         return $company['companyName'];
  4576.                     }, $userAccessList);
  4577.                     return $this->render(
  4578.                         '@Application/pages/dashboard/index_central_landing.html.twig',
  4579.                         [
  4580.                             'page_title' => 'Central Landing',
  4581.                             'companyNames' => $companyName
  4582.                         ]
  4583.                     );
  4584.                 }
  4585.             } else {
  4586.                 if ($systemType == '_CENTRAL_') {
  4587.                     $userAccessList $session->get('userAccessList', []);
  4588.                     $companyName array_map(function ($company) {
  4589.                         return $company['companyName'];
  4590.                     }, $userAccessList);
  4591.                     $modifiedRequest $request->duplicate(
  4592.                         null,
  4593.                         array_merge($request->request->all(), ['appId' => $request->request->get('appid')])
  4594.                     );
  4595.                     $response $this->EmployeeAddUsingQrCodeCentralAction($modifiedRequest);
  4596. //                    if ($CurrentRoute == 'employee_add_by_qr_api')
  4597.                     {
  4598.                         return $response;
  4599.                     }
  4600. //                    return $this->render(
  4601. //                        'ApplicationBundle:pages/dashboard:index_central_landing.html.twig',
  4602. //                        [
  4603. //                            'page_title' => 'Central Landing',
  4604. //                            'companyNames' => $companyName
  4605. //                        ]
  4606. //                    );
  4607.                 }
  4608.             }
  4609.         } else {
  4610.             $company $request->get('company');
  4611.             $em_goc $this->getDoctrine()->getManager('company_group');
  4612.             $company $em_goc->getRepository("CompanyGroupBundle\\Entity\\CompanyGroup")->findOneBy(['appId' => $request->get('appid')]);
  4613.             return $this->render(
  4614.                 '@Application/pages/dashboard/employee_add_by_qr.html.twig',
  4615.                 [
  4616.                     'page_title' => 'Company Invitation',
  4617.                     'company' => $company
  4618.                 ]
  4619.             );
  4620.         }
  4621.     }
  4622.     public function EmployeeOnboardUsingQrAction(Request $request): JsonResponse
  4623.     {
  4624.         $email $request->get('email');
  4625.         $isAjax $request->isXmlHttpRequest();
  4626.         $currentRoute $request->attributes->get('_route');
  4627.         if (!$email) {
  4628.             if ($isAjax) {
  4629.                 return new JsonResponse(['status' => 'error''message' => 'Email is required.']);
  4630.             } else {
  4631.                 throw $this->createNotFoundException("Email is missing.");
  4632.             }
  4633.         }
  4634.         $em_goc $this->getDoctrine()->getManager('company_group');
  4635.         $user $em_goc->getRepository("CompanyGroupBundle\\Entity\\EntityApplicantDetails")->findOneBy(['email' => $email]);
  4636.         if (!$user) {
  4637.             if ($isAjax) {
  4638.                 return new JsonResponse(['status' => 'error''message' => 'Applicant not found.']);
  4639.             } else {
  4640.                 throw $this->createNotFoundException("Applicant not found.");
  4641.             }
  4642.         }
  4643.         $payloadUrl $this->generateUrl('employee_onboard_by_qr_api', [
  4644.             'email' => $user->getEmail(),
  4645.             'applicantId' => $user->getApplicantId(),
  4646.             'employeeQr' => 1
  4647.         ], UrlGeneratorInterface::ABSOLUTE_URL);
  4648.         if ($currentRoute === 'employee_onboard') {
  4649.             return new JsonResponse([
  4650.                 'status' => 'success',
  4651.                 'data' => [
  4652.                     'applicantId' => $user->getApplicantId(),
  4653.                     'username' => $user->getUsername(),
  4654.                     'email' => $user->getEmail(),
  4655.                     'firstName' => $user->getFirstname(),
  4656.                     'lastName' => $user->getLastname(),
  4657.                     'link' => $payloadUrl
  4658.                 ]
  4659.             ]);
  4660.         }
  4661.         if ($isAjax) {
  4662.             return new JsonResponse([
  4663.                 'status' => 'success',
  4664.                 'data' => [
  4665.                     'id' => $user->getApplicantId(),
  4666.                     'email' => $user->getEmail(),
  4667.                     'name' => $user->getFirstname() . ' ' $user->getLastname(),
  4668.                     'dob' => $user->getDob() ? $user->getDob()->format('Y-m-d') : null,
  4669.                 ]
  4670.             ]);
  4671.         }
  4672.         $companies $request->getSession()->get('userAccessList', []);
  4673.         return $this->render('@Application/pages/dashboard/qr_onboard_result.html.twig', [
  4674.             'page_title' => 'Onboarding',
  4675.             'applicant' => $user,
  4676.             'companies' => $companies
  4677.         ]);
  4678.     }
  4679.     public function OnboardUserToCompanyAction(Request $request)
  4680.     {
  4681.         $systemType $this->container->hasParameter('system_type') ? $this->container->getParameter('system_type') : '_ERP_';
  4682.         $currentRoute $request->attributes->get('_route');
  4683.         if ($systemType !== '_CENTRAL_') {
  4684.             throw new \Exception("This action must be called from CENTRAL system.");
  4685.         }
  4686.         $email $request->request->get('email');
  4687.         $applicantId $request->request->get('applicant_id');
  4688.         $appId $request->request->get('company_id');
  4689.         $userType $request->request->get('user_type');
  4690.         if (!$email || !$appId || !$userType) {
  4691.             $this->addFlash('error''Missing required fields.');
  4692.             return new JsonResponse(['status' => 'error''message' => 'Missing required fields.']);
  4693.         }
  4694.         $em $this->getDoctrine()->getManager('company_group');
  4695.         $applicant $em->getRepository("CompanyGroupBundle\\Entity\\EntityApplicantDetails")->findOneBy(['email' => $email]);
  4696.         if (!$applicant) {
  4697.             $this->addFlash('error''Applicant not found.');
  4698.             return $this->redirectToRoute('central_landing');
  4699.         }
  4700.         $userAppIds json_decode($applicant->getUserAppIds(), true);
  4701.         if (!is_array($userAppIds)) {
  4702.             $userAppIds = [];
  4703.         }
  4704.         if (!in_array($appId$userAppIds)) {
  4705.             $userAppIds[] = $appId;
  4706.             $applicant->setUserAppIds(json_encode($userAppIds));
  4707.         }
  4708.         $userTypesByAppIds json_decode($applicant->getUserTypesByAppIds(), true) ?: [];
  4709.         $userTypesByAppIds[$appId] = array((int)$userType);
  4710.         $applicant->setUserTypesByAppIds(json_encode($userTypesByAppIds));
  4711.         $em->persist($applicant);
  4712.         $em->flush();
  4713.         $companyRepo $this->getDoctrine()->getManager('company_group')->getRepository("CompanyGroupBundle\\Entity\\CompanyGroup");
  4714.         $targetCompany $companyRepo->findOneBy(['appId' => $appId]);
  4715.         if (!$targetCompany) {
  4716.             $this->addFlash('error''Target company not found.');
  4717.             return $this->redirectToRoute('central_landing');
  4718.         }
  4719.         $serverList MiscActions::getServerListById(                     $this->container->getParameter('database_user'),                     $this->container->getParameter('database_password'),                     $this->container->hasParameter('server_access_list') ?$this->container->getParameter('server_access_list') :[]                 );
  4720.         $serverId $targetCompany->getCompanyGroupServerId();
  4721.         $appId $targetCompany->getAppId();
  4722.         if (!isset($serverList[$serverId])) {
  4723.             $this->addFlash('error''Server configuration not found.');
  4724.             return $this->redirectToRoute('central_landing');
  4725.         }
  4726.         // Find correct companyId from session userAccessList using appId
  4727.         $session $request->getSession();
  4728.         $userAccessList $session->get('userAccessList', []);
  4729.         $resolvedCompanyId null;
  4730.         foreach ($userAccessList as $access) {
  4731.             if (isset($access['appId']) && $access['appId'] == $appId) {
  4732.                 $resolvedCompanyId $access['companyId'];
  4733.                 break;
  4734.             }
  4735.         }
  4736.         if (!$resolvedCompanyId) {
  4737.             $this->addFlash('error''Could not resolve companyId from session for the given appId.');
  4738.             return $this->redirectToRoute('central_landing');
  4739.         }
  4740.         $imagePath $this->container->getParameter('kernel.root_dir') . '/../web/' $applicant->getImage();
  4741.         $imageFile null;
  4742.         if ($applicant->getImage() && file_exists($imagePath)) {
  4743.             $mime mime_content_type($imagePath);
  4744.             $name pathinfo($imagePathPATHINFO_BASENAME);
  4745.             $imageFile = new \CURLFile($imagePath$mime$name);
  4746.         }
  4747.         // Prepare userData
  4748.         $userData = [];
  4749.         $getters array_filter(get_class_methods($applicant), function ($method) {
  4750.             return strpos($method'get') === 0;
  4751.         });
  4752.         foreach ($getters as $getter) {
  4753.             if (in_array($getter, ['getCreatedAt''getUpdatedAt''getImage'])) continue;
  4754.             $value $applicant->$getter();
  4755.             $userData[$getter] = $value instanceof \DateTime $value->format('Y-m-d') : $value;
  4756.         }
  4757.         $userData['getUserAppIds'] = json_encode($userAppIds);
  4758.         $userData['getUserTypesByAppIds'] = json_encode($userTypesByAppIds);
  4759.         $postFields = [
  4760.             'userData' => json_encode([$userData]),
  4761.             'appIds' => $appId,
  4762.             'userIds' => $applicantId,
  4763.             'companyId' => $resolvedCompanyId,
  4764.             'userType' => $userType,
  4765.             'imageFile' => $imageFile
  4766.         ];
  4767.         if ($imageFile) {
  4768.             $postFields['file_' $applicant->getApplicantId()] = $imageFile;
  4769.         }
  4770.         $url $serverList[$serverId]['absoluteUrl'] . '/OnBoardCentralUserToErp';
  4771.         $curl curl_init();
  4772.         curl_setopt_array($curl, [
  4773.             CURLOPT_RETURNTRANSFER => 1,
  4774.             CURLOPT_POST => 1,
  4775.             CURLOPT_URL => $url,
  4776.             CURLOPT_POSTFIELDS => $postFields,
  4777.             CURLOPT_CONNECTTIMEOUT => 10,
  4778.             CURLOPT_SSL_VERIFYPEER => false,
  4779.             CURLOPT_SSL_VERIFYHOST => false,
  4780.         ]);
  4781.         $response curl_exec($curl);
  4782.         $curlError curl_error($curl);
  4783.         curl_close($curl);
  4784.         $responseObj json_decode($responsetrue);
  4785.         if ($currentRoute === 'employee_onboard_api') {
  4786.             return new JsonResponse(
  4787.                 $responseObj
  4788.             );
  4789.         }
  4790.         if (!empty($responseObj['success'])) {
  4791.             $this->addFlash('success''Applicant onboarded and synced to ERP.');
  4792.         } else {
  4793.             $this->addFlash('warning''Onboarded, but ERP sync may have failed. Check logs.');
  4794.         }
  4795.         return $this->redirectToRoute('central_landing');
  4796.     }
  4797.     public function OnBoardCentralUserToErpAction(Request $request)
  4798.     {
  4799.         $systemType $this->container->hasParameter('system_type') ? $this->container->getParameter('system_type') : '_ERP_';
  4800.         if ($systemType === '_CENTRAL_') {
  4801.             return new JsonResponse(['success' => false'message' => 'Invalid system type.']);
  4802.         }
  4803.         $userDataJson $request->get('userData');
  4804.         $userDataList json_decode($userDataJsontrue);
  4805.         if (!$userDataList || !is_array($userDataList)) {
  4806.             return new JsonResponse(['success' => false'message' => 'Invalid or missing userData.']);
  4807.         }
  4808.         $userData $userDataList[0] ?? null;
  4809.         if (!$userData || empty($userData['getApplicantId'])) {
  4810.             return new JsonResponse(['success' => false'message' => 'Missing applicant ID.']);
  4811.         }
  4812.         $em_goc $this->getDoctrine()->getManager('company_group');
  4813.         $globalId $userData['getApplicantId'];
  4814.         $appIds $request->get('appIds');
  4815.         $userIds $request->get('userIds');
  4816.         $companyId $request->get('companyId');
  4817.         $company $em_goc->getRepository("CompanyGroupBundle\\Entity\\CompanyGroup")->findOneBy(['appId' => $appIds]);
  4818.         if (!$company) {
  4819.             return new JsonResponse(['success' => false'message' => 'Target company not found.']);
  4820.         }
  4821.         $connector $this->container->get('application_connector');
  4822.         $connector->resetConnection(
  4823.             'default',
  4824.             $company->getDbName(),
  4825.             $company->getDbUser(),
  4826.             $company->getDbPass(),
  4827.             $company->getDbHost(),
  4828.             true
  4829.         );
  4830.         $em $this->getDoctrine()->getManager();
  4831.         $user $em->getRepository('ApplicationBundle\\Entity\\SysUser')->findOneBy([
  4832.             'globalId' => $globalId
  4833.         ]);
  4834.         if (!$user) {
  4835.             $user = new \ApplicationBundle\Entity\SysUser();
  4836.             $user->setGlobalId($globalId);
  4837.         } else {
  4838.             return new JsonResponse([
  4839.                 'status' => 'info',
  4840.                 'message' => 'User is already onboarded',
  4841.                 'userId' => $user->getUserId(),
  4842.                 'redirectUrl' => 'dashboard'
  4843.             ]);
  4844.         }
  4845.         $setterMap = [
  4846.             'getUsername' => 'setUserName',
  4847.             'getEmail' => 'setEmail',
  4848.             'getPassword' => 'setPassword',
  4849.             'getDeviceId' => 'setDeviceId',
  4850.             'getDeviceIdLockedFlag' => 'setDeviceIdLockedFlag',
  4851.             'getLockDeviceIdOnNextLoginFlag' => 'setLockDeviceIdOnNextLoginFlag',
  4852.             'getOAuthUniqueId' => 'setOAuthUniqueId',
  4853.             'getOAuthEmail' => 'setOAuthEmail',
  4854.             'getSyncFlag' => 'setSyncFlag',
  4855.             'getFirstname' => 'setName',
  4856.         ];
  4857.         $user->setUserAppId($appIds);
  4858.         $user->setUserAppIdList(json_encode([$appIds]));
  4859.         $user->setStatus(1);
  4860.         foreach ($setterMap as $getter => $setter) {
  4861.             if (isset($userData[$getter]) && method_exists($user$setter)) {
  4862.                 $user->$setter($userData[$getter]);
  4863.             }
  4864.         }
  4865.         $fullName trim(($userData['getFirstname'] ?? '') . ' ' . ($userData['getLastname'] ?? ''));
  4866.         if (!empty($fullName)) {
  4867.             $user->setName($fullName);
  4868.         }
  4869.         $imagePathToSet '';
  4870.         $uploadedFile $request->files->get('file_' $globalId);
  4871.         if ($uploadedFile) {
  4872.             $uploadDir $this->getParameter('kernel.project_dir') . '/web/uploads/UserImage/';
  4873.             if (!file_exists($uploadDir)) {
  4874.                 mkdir($uploadDir0777true);
  4875.             }
  4876.             $filename 'user_' $globalId '.' $uploadedFile->guessExtension();
  4877.             $uploadedFile->move($uploadDir$filename);
  4878.             $imagePathToSet 'uploads/UserImage/' $filename;
  4879.             $user->setImage($imagePathToSet);
  4880.         }
  4881.         $user->setUserType(1);
  4882.         $em->persist($user);
  4883.         $em->flush();
  4884.         $employee $em->getRepository('ApplicationBundle\\Entity\\Employee')->findOneBy([
  4885.             'userId' => $user->getUserId()
  4886.         ]);
  4887.         if (!$employee) {
  4888.             $employee = new \ApplicationBundle\Entity\Employee();
  4889.             $employee->setUserId($user->getUserId());
  4890.             $employee->setDateOfAddition(new \DateTime());
  4891.         }
  4892.         $employee->setFirstName($userData['getFirstname'] ?? null);
  4893.         $employee->setLastName($userData['getLastname'] ?? null);
  4894.         $employee->setName(trim(($userData['getFirstname'] ?? '') . ' ' . ($userData['getLastname'] ?? '')));
  4895.         $employee->setEmail($userData['getEmail'] ?? null);
  4896.         $employee->setEmmContact($userData['getEmmContact'] ?? null);
  4897.         $employee->setCurrentAddress($userData['getCurrAddr'] ?? null);
  4898.         $employee->setPermanentAddress($userData['getPermAddr'] ?? null);
  4899.         $employee->setCompanyId((int)$companyId);
  4900.         $employee->setDepartmentId($userData['getDept'] ?? null);
  4901.         $employee->setBranchId($userData['getBranch'] ?? null);
  4902.         $employee->setPositionId($userData['getDesg'] ?? null);
  4903.         $employee->setSupervisorId($userData['getSupervisor'] ?? null);
  4904.         if (!empty($imagePathToSet)) {
  4905.             $employee->setImage($imagePathToSet);
  4906.         }
  4907.         $employee->setStatus("1");
  4908.         $employee->setLastModifiedDate(new \DateTime());
  4909.         $em->persist($employee);
  4910.         $em->flush();
  4911.         $employeeDetails $em->getRepository('ApplicationBundle\\Entity\\EmployeeDetails')
  4912.             ->findOneBy(['userId' => $user->getUserId()]);
  4913.         if (!$employeeDetails) {
  4914.             $employeeDetails = new \ApplicationBundle\Entity\EmployeeDetails();
  4915.             $employeeDetails->setUserId($user->getUserId());
  4916.         }
  4917.         $employeeDetails->setId($employee->getEmployeeId());
  4918.         $employeeDetails->setFirstname($userData['getFirstname'] ?? null);
  4919.         $employeeDetails->setLastname($userData['getLastname'] ?? null);
  4920.         $employeeDetails->setUsername($userData['getUsername'] ?? null);
  4921.         $employeeDetails->setEmail($userData['getEmail'] ?? null);
  4922.         $employeeDetails->setPassword($userData['getPassword'] ?? null);
  4923.         $employeeDetails->setNid($userData['getNid'] ?? null);
  4924.         $employeeDetails->setSex($userData['getSex'] ?? null);
  4925.         $employeeDetails->setFather($userData['getFather'] ?? null);
  4926.         $employeeDetails->setMother($userData['getMother'] ?? null);
  4927.         $employeeDetails->setSpouse($userData['getSpouse'] ?? null);
  4928.         $employeeDetails->setChild1($userData['getChild1'] ?? null);
  4929.         $employeeDetails->setChild2($userData['getChild2'] ?? null);
  4930.         $employeeDetails->setPhone($userData['getPhone'] ?? null);
  4931.         $employeeDetails->setOfficialPhone($userData['getOfficailPhone'] ?? null);
  4932.         $employeeDetails->setCurrAddr($userData['getCurrAddr'] ?? null);
  4933.         $employeeDetails->setPermAddr($userData['getPermAddr'] ?? null);
  4934.         $employeeDetails->setEmmContact($userData['getEmmContact'] ?? null);
  4935.         if (!empty($userData['getDob'])) {
  4936.             $employeeDetails->setDob(new \DateTime($userData['getDob']));
  4937.         }
  4938.         if (!empty($userData['getJoiningDate'])) {
  4939.             $employeeDetails->setJoiningDate(new \DateTime($userData['getJoiningDate']));
  4940.         }
  4941.         if (!empty($userData['getEmpValidTill'])) {
  4942.             $employeeDetails->setEmpValidTill(new \DateTime($userData['getEmpValidTill']));
  4943.         }
  4944.         if (!empty($userData['getTinValidTill'])) {
  4945.             $employeeDetails->setTinValidTill(new \DateTime($userData['getTinValidTill']));
  4946.         }
  4947.         if (!empty($userData['getMedInsValidTill'])) {
  4948.             $employeeDetails->setMedInsValidTill(new \DateTime($userData['getMedInsValidTill']));
  4949.         }
  4950.         $employeeDetails->setEmpType($userData['getEmpType'] ?? null);
  4951.         $employeeDetails->setEmpCode($userData['getEmpCode'] ?? null);
  4952.         $employeeDetails->setEmployeeLevel($userData['getEmployeeLevel'] ?? null);
  4953.         $employeeDetails->setTin($userData['getTin'] ?? null);
  4954.         $employeeDetails->setSkill($userData['getSkill'] ?? null);
  4955.         $employeeDetails->setEducationData($userData['getEducationData'] ?? null);
  4956.         $employeeDetails->setWorkExperienceData($userData['getWorkExperienceData'] ?? null);
  4957.         $employeeDetails->setApplicationText($userData['getApplicationText'] ?? null);
  4958.         $employeeDetails->setCurrentEmployment($userData['getCurrentEmployment'] ?? null);
  4959.         $employeeDetails->setEmergencyContactNumber($userData['getEmergencyContactNumber'] ?? null);
  4960.         $employeeDetails->setPostalCode($userData['getPostalCode'] ?? null);
  4961.         $employeeDetails->setCountry($userData['getCountry'] ?? null);
  4962.         if (!empty($imagePathToSet)) {
  4963.             $employeeDetails->setImage($imagePathToSet);
  4964.         }
  4965.         $em->persist($employeeDetails);
  4966.         $em->flush();
  4967.         $uploadedFile $request->files->get('file_' $globalId);
  4968.         return new JsonResponse([
  4969.             'success' => true,
  4970.             'globalId' => $globalId,
  4971.             'appIds' => $appIds,
  4972.             'userIds' => $userIds,
  4973.             'hasFile' => $uploadedFile !== null,
  4974.         ]);
  4975.     }
  4976.     public function getIndustryListForAppAction()
  4977.     {
  4978.         $industryList GeneralConstant::$industryList;
  4979.         return new JsonResponse($industryList);
  4980.     }
  4981.     public function getFeatureListAction()
  4982.     {
  4983.         $featureList GeneralConstant::$featureList;
  4984.         return new JsonResponse($featureList);
  4985.     }
  4986.     public function chooseYourPlanAction()
  4987.     {
  4988.         $plan GeneralConstant::$chooseYourPlan;
  4989.         return new JsonResponse($plan);
  4990.     }
  4991. //    public function getLogindataFromTokenAction(Request $request)
  4992. //    {
  4993. //        $em_goc = $this->getDoctrine()->getManager('company_group');
  4994. //        $sessionData = MiscActions::GetSessionDataFromToken($em_goc, $request->query->get('hbeeSessionToken'))['sessionData'];
  4995. //        return new JsonResponse($sessionData);
  4996. //        $sessionDataa = MiscActions::GetSessionDataFromToken($em_goc, $request->query->get('hbeeSessionToken'))['sessionData'];
  4997. //        return new JsonResponse($sessionDataa);
  4998. //    }
  4999.     public function getLogindataFromTokenAction(Request $request)
  5000.     {
  5001.         $em_goc $this->getDoctrine()->getManager('company_group');
  5002.         $token $request->query->get('hbeeSessionToken');
  5003.         if (!$token) {
  5004.             return new JsonResponse(['error' => 'Missing session token'], 400);
  5005.         }
  5006.         $sessionResult MiscActions::GetSessionDataFromToken($em_goc$token);
  5007.         if (!$sessionResult || !isset($sessionResult['sessionData'])) {
  5008.             return new JsonResponse(['error' => 'Invalid session token or session not found'], 401);
  5009.         }
  5010.         $sessionData $sessionResult['sessionData'];
  5011.         return new JsonResponse($sessionData);
  5012.     }
  5013.    public function packageDetailsAction()
  5014. {
  5015.     $packageDetails GeneralConstant::$packageDetails;
  5016.     return new JsonResponse([
  5017.         'success' => true,
  5018.         'message' => 'Data fetched successfully.',
  5019.         'data' => $packageDetails
  5020.     ]);
  5021. }
  5022.     public function employeeRangeAction()
  5023.     {
  5024.         $employeeRangeForApp GeneralConstant::$employeeRange;
  5025.         return new JsonResponse($employeeRangeForApp);
  5026.     }
  5027.     public function paymentMethodAction()
  5028.     {
  5029.         $paymentMethod GeneralConstant::$paymentMethod;
  5030.         return new JsonResponse($paymentMethod);
  5031.     }
  5032.     public function companyTypeAction()
  5033.     {
  5034.         $companyType GeneralConstant::$companyType;
  5035.         return new JsonResponse(
  5036.             [
  5037.                 'status' => 'success',
  5038.                 'message' => 'Company types retrieved successfully.',
  5039.                 'data' => $companyType,
  5040.             ]
  5041.          );
  5042.     }
  5043.     public function getCountryListAction()
  5044.     {
  5045.         $em_goc $this->getDoctrine()->getManager('company_group');
  5046.         $countryList $em_goc->getRepository('CompanyGroupBundle\\Entity\\EntityCountries')
  5047.             ->createQueryBuilder('C')
  5048.             ->select('C.CountryId''C.code''C.nameEn')
  5049.             ->getQuery()
  5050.             ->getArrayResult();
  5051.         // $formattedList = array_map(function ($country) {
  5052.         //     return [
  5053.         //         'countryId' => $country['countryId'],
  5054.         //         'countryName' => $country['nameEn'],
  5055.         //         'countryCode' => $country['code'],
  5056.         //     ];
  5057.         // }, $countryList);
  5058.         return new JsonResponse([
  5059.             'status' => true,
  5060.             'message' => 'Country list fetched successfully',
  5061.             'data' => $countryList,
  5062.         ]);
  5063.     }
  5064. public function spotLightSearchAction(Request $request,$queryStr ''){
  5065.     
  5066.     $em $this->getDoctrine()->getManager();
  5067.     $data = [];
  5068.     $data_by_id = [];
  5069.     $session $request->getSession();
  5070.     $entityDetails GeneralConstant::$Entity_list_details
  5071.     if ($queryStr == '_DEFAULT_')
  5072.         $queryStr '';
  5073.     if ($request->request->has('query') && $queryStr == '')
  5074.         $queryStr $request->request->get('query');
  5075.     if ($queryStr == '_DEFAULT_')
  5076.         $queryStr '';
  5077.     $queryStr str_ireplace('_FSLASH_''/'$queryStr);
  5078.     //module
  5079.     $filterQryForCriteria "select * from sys_module where 1=1 and module_name  like '%" $queryStr "%'  limit 10";
  5080.     $get_kids_sql $filterQryForCriteria;
  5081.     $stmt $em->getConnection()->fetchAllAssociative($get_kids_sql);
  5082.     
  5083.     $get_kids $stmt;
  5084.     $productId 0;
  5085.     $absoluteUrl $this->generateUrl('dashboard', [], UrlGenerator::ABSOLUTE_URL);
  5086.     if (!empty($get_kids)) {
  5087.         foreach ($get_kids as $product) {
  5088.             $router $this->container->get('router');
  5089.             $routeName $product['module_route'];
  5090.             if ($router->getRouteCollection()->get($routeName)) {
  5091.                 $pa            = array();
  5092.                 $pa['id']      = $product['module_id'];
  5093.                 $pa['name']    = $product['module_name'];
  5094.                 $pa['type']    = 'module';
  5095. //            $pa['url']     = $absoluteUrl . '/' . $product['module_route'];
  5096.                 $pa['url']     = $this->generateUrl($product['module_route'], [], UrlGenerator::ABSOLUTE_URL);
  5097.                 $data[] = $pa;
  5098.             } else {
  5099.                 // treat as non-route
  5100. //                $pa['url'] = $routeName; // or custom fallback
  5101.             }
  5102.         }
  5103.     }
  5104.     // supplier
  5105.     $get_kids $em->getConnection()->fetchAllAssociative(
  5106.         "select * from acc_suppliers where supplier_name like '%" $queryStr "%' limit 10"
  5107.     );
  5108.     $url $this->generateUrl('supplier_profile');
  5109.     if (!empty($get_kids)) {
  5110.         foreach ($get_kids as $product) {
  5111.             $pa           = array();
  5112.             $pa['id']     = $product['supplier_id'];
  5113.             $pa['name']   = $product['supplier_name'];
  5114.             $pa['type']   = 'supplier';
  5115.             $pa['url']    = rtrim($absoluteUrl'/') . '/' ltrim($url'/') . '?ex_s_id=' $product['supplier_id'];
  5116.             $data[] = $pa;
  5117.         }
  5118.     }
  5119.     // client
  5120.     $get_kids $em->getConnection()->fetchAllAssociative(
  5121.         "select * from acc_clients where client_name like '%" $queryStr "%' limit 10"
  5122.     );
  5123.     $url $this->generateUrl('client_profile');
  5124.     if (!empty($get_kids)) {
  5125.         foreach ($get_kids as $product) {
  5126.             $pa           = array();
  5127.             $pa['id']     = $product['client_id'];
  5128.             $pa['name']   = $product['client_name'];
  5129.             $pa['type']   = 'client';
  5130.             $pa['url']    = rtrim($absoluteUrl'/') . '/' trim($url'/') . '/' $product['client_id'];
  5131.             $data[] = $pa;
  5132.         }
  5133.     }
  5134.     // document (approval)
  5135.     $get_kids $em->getConnection()->fetchAllAssociative(
  5136.         "select * from approval where document_hash like '%" $queryStr "%' limit 10"
  5137.     );
  5138.     if (!empty($get_kids)) {
  5139.         foreach ($get_kids as $product) {
  5140.             try {
  5141.                 $viewUrl $this->generateUrl(
  5142.                     $entityDetails[$product['entity']]['entity_view_route_path_name']
  5143.                 );
  5144.                 $pa           = array();
  5145.                 $pa['id']     = $product['id'];
  5146.                 $pa['name']   = $product['document_hash'];
  5147.                 $pa['type']   = 'document';
  5148.                 $pa['url']    = rtrim($absoluteUrl'/') . '/' trim($viewUrl'/') . '/' $product['entity_id'];
  5149.                 $data[] = $pa;
  5150.             } catch (\Exception $e) { /* skip if route undefined */ }
  5151.         }
  5152.     }
  5153.     return new JsonResponse(array(
  5154.         'success' => true,
  5155.         'data'    => $data,
  5156.     ));
  5157. }
  5158.     public function getMlDataAction()
  5159.     {
  5160.         $data GeneralConstant::$dataFromMl;
  5161.         return new JsonResponse($data);
  5162.     }
  5163.     public function UploadDocumentsAction(Request $request)
  5164.     {
  5165.         $session $request->getSession();
  5166.         $em $this->getDoctrine()->getManager();
  5167.         return $this->render(
  5168.             '@Application/pages/dashboard/upload_documents.html.twig',
  5169.             array(
  5170.                 'page_title' => 'Upload Documents',
  5171.             )
  5172.         );
  5173.     }
  5174. }