src/Controller/SalesforceController.php line 645

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Autoresponder;
  4. use App\Entity\AutoResponderLog;
  5. use App\Entity\Comm;
  6. use App\Entity\Customer;
  7. use App\Factory\MailerFactory;
  8. use App\Utils\BigCommerceClient;
  9. use App\Utils\BigCommerceConfig;
  10. use App\Utils\WebhookManager;
  11. use App\Utils\SalesforceConfig;
  12. use Psr\Log\LoggerInterface;
  13. use Bigcommerce\Api\Client as Bigcommerce;
  14. use Doctrine\ORM\EntityManagerInterface;
  15. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  16. use Symfony\Component\HttpFoundation\Request;
  17. use Symfony\Component\HttpFoundation\JsonResponse;
  18. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  19. use App\Repository\SalesAgentRepository;
  20. use App\Repository\MarketSegmentRepository;
  21. use App\Repository\CustomerGroupRepository;
  22. use Symfony\Component\HttpFoundation\Response;
  23. use App\Entity\SalesAgent;
  24. use App\Entity\MarketSegment;
  25. use App\Entity\CustomerGroup;
  26. use Symfony\Component\HttpFoundation\RedirectResponse;
  27. use App\Utils\bjsmasth\salesforce_api\CRUD;
  28. use App\Service\Customer\SalesForce\ConverterInterface as SFField;
  29. class SalesforceController extends AbstractController
  30. {
  31.     const ACTION_ADD_ORDER_WEBHOOK 'order_add_webhook';
  32.     const ACTION_RECREATE_ORDER_WEBHOOK 'order_recreate_webhook';
  33.     const DT_FORMAT = \DateTime::ISO8601;
  34.     public $module_name 'salesforce';
  35.     public function product_discount($parent_id$products,$product_options_array)
  36.     {
  37.         $total_price 0;
  38.         foreach ($products as $product)
  39.         {
  40.             if ($product->parent_order_product_id == $parent_id)
  41.             {
  42.                 $product_price Bigcommerce::getProduct($product->product_id);
  43.                 if (!is_null($product_options_array[$product->product_id]))
  44.                 {
  45.                     $qty=$product_options_array[$product->product_id];
  46.                     $total_price $total_price + ($product_price->price*$qty);
  47.                 }
  48.                 else {
  49.                     $total_price $total_price + ($product_price->price);
  50.                 }
  51.             }
  52.         }
  53.         return $total_price;
  54.     }
  55.     public function index()
  56.     {
  57.         return $this->render('/salesforce/salesforce.html.twig');
  58.     }
  59.     public function Settings(WebhookManager $hook)
  60.     {
  61.         $twigGlobals $this->container->get('twig')->getGlobals();
  62.         $orderAddHookInfo $hook->getWebhookInfoForRender($twigGlobals['create_order_scope'], $this->module_name);
  63.         $orderUpdateHookInfo $hook->getWebhookInfoForRender($twigGlobals['update_order_scope'], $this->module_name);
  64.         $orderStatusUpdateHookInfo $hook->getWebhookInfoForRender($twigGlobals['update_order_status_scope'], $this->module_name);
  65.         $addHookDestination $this->generateUrl('salesforce_hook_create', [],UrlGeneratorInterface::ABSOLUTE_URL);
  66.         $delHookDestination $this->generateUrl('salesforce_hook_delete', [],UrlGeneratorInterface::ABSOLUTE_URL);
  67.         $webhooks = [
  68.             'order' => [
  69.                 'order_add_hook' => [
  70.                     'name' => 'Order create webhook',
  71.                     'obj' => $orderAddHookInfo['obj'],
  72.                     'scope' => $twigGlobals['create_order_scope'],
  73.                     'aid' => 'order_add_webhook',
  74.                     'last_webhook_received' => $orderAddHookInfo['lastTimeReceived'],
  75.                 ],
  76.                 'order_update_hook' => [
  77.                     'name' => 'Order update webhook',
  78.                     'obj' => $orderUpdateHookInfo['obj'],
  79.                     'scope' => $twigGlobals['update_order_scope'],
  80.                     'aid' => 'order_update_webhook',
  81.                     'last_webhook_received' => $orderUpdateHookInfo['lastTimeReceived'],
  82.                 ],
  83.                 'order_status_update_hook' => [
  84.                     'name' => 'Order status update webhook',
  85.                     'obj' => $orderStatusUpdateHookInfo['obj'],
  86.                     'scope' => $twigGlobals['update_order_status_scope'],
  87.                     'aid' => 'order_update_webhook',
  88.                     'last_webhook_received' => $orderStatusUpdateHookInfo['lastTimeReceived'],
  89.                 ],
  90.                 'params' => [
  91.                     'route' => 'salesforce_CreateOrder',
  92.                     'slug' => 'salesforce_CreateOrder',
  93.                     'action_add' => self::ACTION_ADD_ORDER_WEBHOOK,
  94.                     'action_del' => self::ACTION_RECREATE_ORDER_WEBHOOK,
  95.                     'url_add' => $addHookDestination,
  96.                     'url_del' => $delHookDestination
  97.                 ]
  98.             ],
  99.         ];
  100.         $view = [
  101.             'webhook_groups' => $webhooks
  102.         ];
  103.         return $this->render('/salesforce/setting.html.twig'$view);
  104.     }
  105.     public function SalesAgentDefault($idLoggerInterface $loggerRequest $requestSalesAgentRepository $salesAgentRepositoryWebhookManager $hookEntityManagerInterface $entityManager)
  106.     {
  107.         // find an active record and make it make it not active
  108.         $salesagent_default_remove $salesAgentRepository->findOneBy(['active' => 1]);
  109.         if (!is_null($salesagent_default_remove))
  110.         {
  111.             $salesagent_default_remove->setActive(0);
  112.             $entityManager->persist($salesagent_default_remove);
  113.             $entityManager->flush(); // default  column remove
  114.         }
  115.         // find the specified record and make it active
  116.         $salesagent_default $salesAgentRepository->find($id);
  117.         $salesagent_default->setActive(1);
  118.         $entityManager->persist($salesagent_default);
  119.         $entityManager->flush(); // set default  column
  120.         $destination $this->generateUrl('salesforcesales_agent', [], UrlGeneratorInterface::ABSOLUTE_URL);
  121.         return new RedirectResponse($destination);
  122.     }
  123.     public function SalesAgent(LoggerInterface $loggerRequest $requestSalesAgentRepository $salesAgentRepositoryWebhookManager $hookEntityManagerInterface $entityManager)
  124.     {
  125.         $action $request->request->get('action');
  126.         if ($action == "save")
  127.         {
  128.             $bigcommerce_agent_name $request->request->get('bigcommerce_agent_name');
  129.             $salesforcesales_agent_id $request->request->get('salesforcesales_agent_id');
  130.             $salesagent = new SalesAgent();
  131.             $salesagent->setName($bigcommerce_agent_name);
  132.             $salesagent->setSalesforceId($salesforcesales_agent_id);
  133.             $entityManager->persist($salesagent);
  134.             $entityManager->flush();
  135.         }
  136.         if ($action == "delete")
  137.         {
  138.             $id $request->request->get('agent_id');
  139.             $salesagent $salesAgentRepository->find($id);
  140.             $salesagent->setDeleted(true);
  141.             $entityManager->persist($salesagent);
  142.             $entityManager->flush();
  143.             $response = new JsonResponse();
  144.             $json_data['error'] = 0;
  145.             $json_data['msg'] = 'Deleted successfully';
  146.             $response->setData($json_data);
  147.             $response->headers->set('Content-Type''application/json');
  148.             $response->getContent();
  149.             return $response;
  150.         }
  151.         $customerowner $salesAgentRepository->findAll();
  152.         $view = array(
  153.             'customerowner' => $customerowner,
  154.         );
  155.         return $this->render('/salesforce/salesagent.html.twig',
  156.             $view
  157.         );
  158.     }
  159.     public function MarketSegmentDefault($idMarketSegmentRepository $MarketSegmentRepositoryWebhookManager $hookEntityManagerInterface $entityManager)
  160.     {
  161.         // find an active record and make it make it not active
  162.         $marketsegment_default_remove $MarketSegmentRepository->findOneBy(['active' => 1]);
  163.         if (!is_null($marketsegment_default_remove))
  164.         {
  165.             $marketsegment_default_remove->setActive(0);
  166.             $entityManager->persist($marketsegment_default_remove);
  167.             $entityManager->flush(); // default  column remove
  168.         }
  169.         // find the specified record and make it active
  170.         $marketsegment_default $MarketSegmentRepository->find($id);
  171.         $marketsegment_default->setActive(1);
  172.         $entityManager->persist($marketsegment_default);
  173.         $entityManager->flush(); // set default  column
  174.         $destination $this->generateUrl('salesforcemarket_segment', [], UrlGeneratorInterface::ABSOLUTE_URL);
  175.         return new RedirectResponse($destination);
  176.         $json_data['error'] = 0;
  177.         $json_data['msg'] = 'successfully updated';
  178.         $json_data['hook_id'] = 0;
  179.         $response = new JsonResponse();
  180.         $response->setData($json_data);
  181.         $response->headers->set('Content-Type''application/json');
  182.         $response->getContent();
  183.         return $response;
  184.     }
  185.     public function MarketSegment(LoggerInterface $loggerRequest $requestMarketSegmentRepository $MarketSegmentRepositoryWebhookManager $hookEntityManagerInterface $entityManager)
  186.     {
  187.         $action $request->request->get('action');
  188.         if ($action == "save")
  189.         {
  190.             $bigcommerce_name $request->request->get('bigcommerce_name');
  191.             $salesforce_name $request->request->get('salesforce_name');
  192.             $marketsegment = new MarketSegment();
  193.             $marketsegment->setBigcommerceName($bigcommerce_name);
  194.             $marketsegment->setSalesforceName($salesforce_name);
  195.             $entityManager->persist($marketsegment);
  196.             $entityManager->flush();
  197.         }
  198.         if ($action == "delete")
  199.         {
  200.             $id $request->request->get('agent_id');
  201.             $marketsegment $MarketSegmentRepository->find($id);
  202.             $marketsegment->setDeleted(true);
  203.             $entityManager->persist($marketsegment);
  204.             $entityManager->flush();
  205.             $response = new JsonResponse();
  206.             $json_data['error'] = 0;
  207.             $json_data['msg'] = 'Deleted successfully';
  208.             $response->setData($json_data);
  209.             $response->headers->set('Content-Type''application/json');
  210.             $response->getContent();
  211.             return $response;
  212.         }
  213.         $marketsegment $MarketSegmentRepository->findAll();
  214.         $view = array(
  215.             'marketsegment' => $marketsegment,
  216.         );
  217.         return $this->render('/salesforce/marketsegment.html.twig',
  218.             $view
  219.         );
  220.     }
  221.     public function CustomerGroup(LoggerInterface $loggerRequest $requestCustomerGroupRepository $CustomerGroupRepositoryWebhookManager $hookEntityManagerInterface $entityManager)
  222.     {
  223.         $action $request->request->get('action');
  224.         if ($action == "save")
  225.         {
  226.             $bigcommerce_name $request->request->get('bigcommerce_name');
  227.             $salesforce_name $request->request->get('salesforce_name');
  228.             $customergroup = new CustomerGroup();
  229.             $customergroup->setBigcommerceName($bigcommerce_name);
  230.             $customergroup->setSalesforceName($salesforce_name);
  231.             $entityManager->persist($customergroup);
  232.             $entityManager->flush();
  233.         }
  234.         if ($action == "delete")
  235.         {
  236.             $id $request->request->get('agent_id');
  237.             $customergroup $CustomerGroupRepository->find($id);
  238.             $customergroup->setDeleted(true);
  239.             $entityManager->persist($customergroup);
  240.             $entityManager->flush();
  241.             $response = new JsonResponse();
  242.             $json_data['error'] = 0;
  243.             $json_data['msg'] = 'Deleted successfully';
  244.             $response->setData($json_data);
  245.             $response->headers->set('Content-Type''application/json');
  246.             $response->getContent();
  247.             return $response;
  248.         }
  249.         $customergroup $CustomerGroupRepository->findAll();
  250.         $view = array(
  251.             'customergroup' => $customergroup,
  252.         );
  253.         return $this->render('/salesforce/customergroup.html.twig',
  254.             $view
  255.         );
  256.     }
  257.     /*
  258.     * call create order/order-status webhook
  259.     */
  260.     public function hook_order_create(Request $requestWebhookManager $hook)
  261.     {
  262.         return $hook->create($request$this->module_name);
  263.     }
  264.     /*
  265.     * call recreate order/order-status webhook
  266.     */
  267.     public function hook_delete(LoggerInterface $loggerRequest $requestWebhookManager $hookBigCommerceConfig $bigCommerceConfig)
  268.     {
  269.         return $hook->delete($request$this->module_name);
  270.     }
  271.     /**
  272.      * Sends email with info
  273.      *
  274.      * @param string $subject
  275.      * @param string $body
  276.      */
  277.     protected function sendNotification($subject$body)
  278.     {
  279.         if (isset($_ENV['ERROR_EMAIL_ADDRESS'])) {
  280.             $mail MailerFactory::create();
  281.             $mail->addAddress($_ENV['ERROR_EMAIL_ADDRESS']);
  282.             $mail->setFrom('no-reply@heartmath.com');
  283.             $mail->Subject $subject;
  284.             $mail->Body $body;
  285.             $mail->send();
  286.         }
  287.     }
  288.     /**
  289.      * Sends email with exception info
  290.      *
  291.      * @param \Throwable $e
  292.      */
  293.     protected function sendErrorNotification(\Throwable $e)
  294.     {
  295.         if (isset($_ENV['SEND_EMAIL_ON_ERROR'], $_ENV['ERROR_EMAIL_ADDRESS']) && $_ENV['SEND_EMAIL_ON_ERROR']) {
  296.             $this->sendNotification(
  297.                 'Synchronization error: ' $e->getMessage(), 
  298.                 (string)$e
  299.             );
  300.         }
  301.     }
  302.     public function CreateTask(
  303.         SalesforceConfig $SalesforceConfig,
  304.         $arLog
  305.         $sf_account_id,
  306.         $task_subject,
  307.         $owner_id,
  308.         $logger
  309.     ) {
  310.         try {
  311.             $task_priority 'Normal';
  312.             $task_status 'Completed';
  313.             $task_subtype 'Email';
  314.             $task_type 'Email';
  315.             $dtFormat $this::DT_FORMAT;
  316.             $bc_date $arLog->getCreatedAt();
  317.             $offset timezone_offset_get(new \DateTimeZone('America/Los_Angeles'), $bc_date);
  318.             $offset_interval= \DateInterval::createFromDateString((string)$offset 'seconds');
  319.             $email_date $bc_date->add($offset_interval)->format($this::DT_FORMAT);
  320.             $email_body html_entity_decode(strip_tags($arLog->getBody()),ENT_QUOTES);
  321.             $eventData = [
  322.                 'ActivityDate' => $email_date,
  323.                 'Description' => $email_body,
  324.                 'OwnerID' => $owner_id,
  325.                 'Priority' => $task_priority,
  326.                 'Status' => $task_status,
  327.                 'Subject' => $task_subject,
  328.                 'TaskSubtype' => $task_subtype,
  329.                 'Type' => $task_type,
  330.                 'WhatId' => $sf_account_id
  331.             ];
  332.             // $this->dumpToScreen($eventData, 'eventData');
  333.             $SalesforceConfig->set_config();
  334.             $crud = new CRUD($logger);
  335.             // $message .= "Calling '$instance_url' to create event\n";
  336.             $sf_email_id $crud->create('Task'$eventData);  #returns id
  337.             return array("id" => $sf_email_id"error" => null);
  338.         } catch (\Exception $e) {
  339.             // $message .= "Lead Conversion Failed\n";
  340.             return array("id" => null"error" => $e->getMessage());
  341.         }
  342.     }
  343.     /**
  344.      * Sync Autoresponder emails to Salesforce
  345.      * @param Request $request
  346.      * @return Response
  347.      */
  348.     public function syncAutoresponderEmails(
  349.         Request $request
  350.         SalesforceConfig $SalesforceConfig,
  351.         EntityManagerInterface $entityManager,
  352.         BigCommerceConfig $bigCommerceConfig,
  353.         LoggerInterface $logger,
  354.         SalesAgentRepository $salesAgentRepository
  355.     ) {
  356.         try {
  357.             $storehash $_ENV['STOREHASH'];
  358.             $config $bigCommerceConfig->get_app_detail();
  359.             Bigcommerce::configure(array(
  360.                 'client_id' => $_ENV['CLIENT_ID'],
  361.                 'auth_token' => $config[$storehash]['access_token'],
  362.                 'store_hash' => $storehash
  363.             ));
  364.             $SalesforceConfig->set_config();
  365.             // Retrieve list of new AutoresponderLogs
  366.             $arLogRepo $entityManager->getRepository(AutoResponderLog::class);
  367.             $arLogs $arLogRepo->findBy(array(
  368.                 'sf_sync_status' => AutoResponderLog::SF_SYNC_STATUS_NEW
  369.             ), array('order_id' => 'ASC''id' => 'ASC'), 10);
  370.             $customerRepo $entityManager->getRepository(Customer::class);
  371.             if (count($arLogs)) {
  372.                 $api_url_path $bigCommerceConfig->get_api_url();
  373.                 $data_string "";
  374.                 $customrequest "GET";
  375.                 $salesagent_default $salesAgentRepository->findOneBy(['active' => 1])->getSalesforceId();
  376.                 $arRepo $entityManager->getRepository(Autoresponder::class);
  377.                 $last_order_id 0;
  378.                 foreach ($arLogs as $arLog) {
  379.                     $order_id $arLog->getOrderId();
  380.                     // $this->dumpToScreen($arLog, 'arLog');
  381.                     // Check if this arLog is from the same order; if it is, 
  382.                     // we don't need to retrieve it again
  383.                     if ($order_id !== $last_order_id) {
  384.                         // Get order and details from BigCommerce
  385.                         $api_url "$api_url_path/v2/orders/".$order_id;
  386.                         $bc_order $SalesforceConfig->curl($api_url$data_string$customrequest);
  387.                         // $this->dumpToScreen($bc_order, 'BC Order');
  388.                         $bc_customer_id $bc_order['customer_id'];
  389.                         $customer $customerRepo->findOneBy(['bc_id' => $bc_customer_id]);
  390.                     }
  391.                     if (!empty($customer)) {
  392.                         // We found a record with a BigCommerce ID corresponding to a Salesforce ID, 
  393.                         // so we can proceed to attach the email.
  394.                         $autoresponder $arRepo->findOneBy(['Sku' => $arLog->getSku()]);
  395.                         if (isset($autoresponder)) {
  396.                             $subject $autoresponder->getSubject();
  397.                         } else {
  398.                             $subject 'AutoResponder SKU Not Found - Default Subject';
  399.                         }
  400.                         $sf_customer_id $customer->getSfId();
  401.                         // $this->dumpToScreen($customerStatus, 'customerStatus');
  402.                         // Mark the record as processing
  403.                         $arLog->setSfSyncStatus(AutoResponderLog::SF_SYNC_STATUS_PROCESSING);
  404.                         $entityManager->persist($arLog);
  405.                         $entityManager->flush();
  406.                         $result $this->CreateTask(
  407.                             $SalesforceConfig,
  408.                             $arLog
  409.                             $sf_customer_id,
  410.                             $subject,
  411.                             $salesagent_default,
  412.                             $logger
  413.                         );
  414.                         if (isset($result['id'])) {
  415.                             $arLog->setSfSyncStatus(AutoResponderLog::SF_SYNC_STATUS_COMPLETE);
  416.                             $entityManager->persist($arLog);
  417.                             $entityManager->flush();
  418.                         } elseif (isset($result['error'])) {
  419.                             $logger->error("Error - SalesforceController syncAutoresponderEmails arLog " $arLog->getId() . "Error: " $result['error']);
  420.                             $arLog->setSfSyncStatus(AutoResponderLog::SF_SYNC_STATUS_ERROR);
  421.                             $entityManager->persist($arLog);
  422.                             $entityManager->flush();
  423.                         } else {
  424.                             //Don't know what happened
  425.                             $logger->error("Unknown Outcome - SalesforceController syncAutoresponderEmails arLog " $arLog->getId());
  426.                             $arLog->setSfSyncStatus(AutoResponderLog::SF_SYNC_STATUS_SKIP);
  427.                             $entityManager->persist($arLog);
  428.                             $entityManager->flush();
  429.                         }
  430.                     } else {
  431.                         // No customer status record found with a BC ID associated to a SF ID. Other 
  432.                         // processes should fill this in, so skip this time around.
  433.                         // $this->dumpToScreen("Order # $order_id sf_id not found", 'Skipped');
  434.                         $logger->info("Autoresponder Email Sync - Order # $order_id sf_id not found. Will retry.");
  435.                         // Mark the record as new so it can be retried
  436.                         $arLog->setSfSyncStatus(AutoResponderLog::SF_SYNC_STATUS_NEW);
  437.                         $entityManager->persist($arLog);
  438.                         $entityManager->flush();
  439.                     }
  440.                     $last_order_id $order_id;
  441.                 }
  442.             }
  443.         } catch (\Exception $e) {
  444.             $logger->error("Error - SalesforceController syncAutoresponderEmails" $e->getMessage());
  445.             $this->sendNotification(
  446.                 'App Error - SalesforceController syncAutoresponderEmails',
  447.                 str_replace("\u0000","",json_encode((array)$eJSON_PRETTY_PRINT))
  448.             );
  449.         }
  450.         $response = new Response();
  451.         // $response->headers->set('Content-Type', 'text/xml');
  452.         // $response->headers->set('Content-Type', 'text/html');
  453.         $response->headers->set('Content-Type''text/html');
  454.         // $this->logger->info("process Orders: " . json_encode((array)$orders));
  455.         return $this->render('salesforce/syncAutoresponderEmails.html.twig', array(
  456.             'arLogs' => $arLogs
  457.         ));
  458.     }
  459.     private function deleteAppsyncCustomer(
  460.         Customer $customer,
  461.         EntityManagerInterface $entityManager,
  462.         LoggerInterface $logger
  463.     ) {
  464.         //Delete the customer record in the db
  465.         $logger->info("SF delete - remove appsync database record: ID: " 
  466.             $customer->getId() . 
  467.             ", Email: " $customer->getEmailAddress() .
  468.             ", BC ID: " $customer->getBcId() .
  469.             ", SF ID: " $customer->getSfId()
  470.         );
  471.         $entityManager->remove($customer);
  472.         $entityManager->flush();                
  473.     }
  474.     /**
  475.      * Move BigCommerce orders to a customer
  476.      *
  477.      * @param array $bcOrders
  478.      * @param int $bcCustomerIdNew
  479.      * @return array Orders data
  480.      */
  481.     private function moveBcOrdersToCustomer(
  482.         $bcOrders
  483.         $bcCustomerIdNew,
  484.         EntityManagerInterface $entityManager,
  485.         LoggerInterface $logger,
  486.         BigCommerceClient $bigCommerceClient
  487.         ): array
  488.     {
  489.         $commRepo $entityManager->getRepository(Comm::class);
  490.         $bc_orders_updated = array();
  491.         foreach ($bcOrders as $bcOrder) {
  492.             $dtEnd = new \DateTime;
  493.             $comm = new Comm();
  494.             $comm->setService(Comm::SERVICE_ORDER);
  495.             $comm->setType(Comm::TYPE_BC_UPDATE);
  496.             $comm->setDtCreated($dtEnd);
  497.             $comm->setStatus(Comm::STATUS_NEW);
  498.             $entityManager->persist($comm);
  499.             $entityManager->flush();
  500.             $commId $comm->getId();
  501.             try {
  502.                 $params = [
  503.                     'customer_id' => $bcCustomerIdNew
  504.                 ];
  505.                 $comm $commRepo->find($commId);
  506.                 $comm->setRequest(__METHOD__ ' BigCommerceClient updateOrder. OrderId: ' $bcOrder->id '. Params: ' $this->encodeJson($params));
  507.                 $logger->info("SalesforceController moveBcOrdersToCustomer: Order ID: $bcOrder->id, Old Customer ID: $bcOrder->customer_id, New Customer ID: $bcCustomerIdNew");
  508.                 $bc_order $bigCommerceClient->updateOrder($bcOrder->id$params);
  509.                 $bc_orders_updated[] = $bc_order;
  510.                 $comm->setContent($this->encodeJson($bc_order));
  511.                 $comm->setStatus(Comm::STATUS_COMPLETE);
  512.                 $entityManager->persist($comm);
  513.                 $entityManager->flush();                
  514.             } catch(\Exception $e) {
  515.                 $logger->error("Error - Comparator moveBcOrdersToCustomer: Order ID: $$bcOrder->id New Customer ID: $bcCustomerIdNew$e->getMessage());
  516.                 $comm->setResponse($this->encodeJson($e));
  517.                 $comm->setStatus(Comm::STATUS_ERROR);
  518.                 $entityManager->persist($comm);
  519.                 $entityManager->flush();
  520.             }
  521.         }
  522.         return $bc_orders_updated;
  523.     }
  524.     /**
  525.      * Get BigCommerce order IDs for specific customer
  526.      *
  527.      * @param int $bcCustomerId
  528.      * @return array Orders data
  529.      */
  530.     private function listBcOrdersByCustomerId(
  531.         $bcCustomerId
  532.         BigCommerceClient $bigCommerceClient,
  533.         EntityManagerInterface $entityManager,
  534.         LoggerInterface $logger
  535.         ): ?array
  536.     {
  537.         $commRepo $entityManager->getRepository(Comm::class);
  538.         $dtEnd = new \DateTime;
  539.         $comm = new Comm();
  540.         $comm->setService(Comm::SERVICE_ORDER);
  541.         $comm->setType(Comm::TYPE_BC_LIST);
  542.         $comm->setDtCreated($dtEnd);
  543.         $comm->setStatus(Comm::STATUS_NEW);
  544.         $entityManager->persist($comm);
  545.         $entityManager->flush();
  546.         $commId $comm->getId();
  547.         try {
  548.             $bc_orders = array();
  549.             $params = [
  550.                 'customer_id' => $bcCustomerId
  551.             ];
  552.             $comm $commRepo->find($commId);
  553.             $comm->setRequest(__METHOD__ ' bigCommerceClient->getOrders. Params: ' $this->encodeJson($params));
  554.             $bc_orders $bigCommerceClient->getOrders($params);
  555.             $comm->setResponse($this->encodeJson($bc_orders));
  556.             $comm->setStatus(Comm::STATUS_COMPLETE);
  557.             $entityManager->persist($comm);
  558.             $entityManager->flush();
  559.             return $bc_orders;
  560.             
  561.         } catch(\Exception $e) {
  562.             $logger->error("Error - Comparator listBcOrdersByCustomerId: " $e->getMessage());
  563.             $comm->setResponse($this->encodeJson($e));
  564.             $comm->setStatus(Comm::STATUS_ERROR);
  565.             $entityManager->persist($comm);
  566.             $entityManager->flush();
  567.         }
  568.         return [];
  569.     }
  570.     /**
  571.      * Salesforce Customer Delete Webhook Endpoint
  572.      * @param Request $request
  573.      * @return Response
  574.      */
  575.     public function CustomerDelete(
  576.         Request $request
  577.         SalesforceConfig $SalesforceConfig,
  578.         EntityManagerInterface $entityManager,
  579.         BigCommerceConfig $bigCommerceConfig,
  580.         LoggerInterface $logger,
  581.         BigCommerceClient $bigCommerceClient,
  582.         \App\Service\Customer\SalesForce\Converter $salesForceCustomerConverter
  583.     ) {
  584.         try {
  585.             $storehash $_ENV['STOREHASH'];
  586.             $config $bigCommerceConfig->get_app_detail();
  587.             BigCommerceClient::configure(array(
  588.                 'client_id' => $_ENV['CLIENT_ID'],
  589.                 'auth_token' => $config[$storehash]['access_token'],
  590.                 'store_hash' => $storehash
  591.             ));
  592.             $SalesforceConfig->set_config();
  593.             $crud = new CRUD($logger);
  594.             // Retrieve list of newly deleted customers
  595.             $commRepo $entityManager->getRepository(Comm::class);
  596.             $comms $commRepo->findBy(array(
  597.                 'service' => Comm::SERVICE_CUSTOMER,
  598.                 'type' => Comm::TYPE_SF_RECEIVE_HOOK,
  599.                 'status' => Comm::STATUS_NEW
  600.             ), array('id' => 'ASC'), 10);
  601.             if (count($comms)) {
  602.                 $customerRepo $entityManager->getRepository(Customer::class);
  603.                 $sfLosers = []; //keep all records that are merge losers
  604.                 foreach ($comms as $comm) {
  605.                     $commId $comm->getId();
  606.                     $comm->setStatus(Comm::STATUS_PROCESSING);
  607.                     $entityManager->persist($comm);
  608.                     $entityManager->flush();
  609.                     $comm $commRepo->find($commId);        
  610.                     $content json_decode($comm->getContent(), true);
  611.                     $sfLosers $content['old'];
  612.                     foreach ($sfLosers as $sfLoser) {
  613.                         $customerId null;
  614.                         $customerEmail null;
  615.                         $customerSageId null;
  616.                         $isBusinessAccount false;
  617.                         $customer null;
  618.                         $customer $customerRepo->findOneBy(['sf_id' => $sfLoser[SFField::FIELD_ID]]);
  619.                         if ($customer) {
  620.                             $customerId $customer->getBcId();
  621.                             $customerEmail $customer->getEmailAddress();
  622.                             $customerSageId $customer->getSageId();
  623.                             $isBusinessAccount $customer->isBusinessAccount();
  624.                         }
  625.                         if (!$customerId) {
  626.                             // No customer found in appsync db. For now, we will dump out of the process. 
  627.                             // In prod, every SF customer SHOULD be in BC and the appsync db. If it is not, 
  628.                             // something is wrong with this record and we will ignore for now.
  629.                             $logger->error(__METHOD__ ' Customer not found in appsync db: ' $sfLoser['Id']);
  630.                             $comm->setStatus(Comm::STATUS_COMPLETE);
  631.                             $entityManager->persist($comm);
  632.                             $entityManager->flush();
  633.                             break;
  634.                         }
  635.                         $master null;
  636.                         $merged false// true if a merge with a master record, false if a straight delete in SF
  637.                         if (array_key_exists(SFField::FIELD_MASTER_RECORD_ID$sfLoser) && $sfLoser[SFField::FIELD_MASTER_RECORD_ID]) { //merge
  638.                             $merged true;
  639.                             $masterSfId $sfLoser[SFField::FIELD_MASTER_RECORD_ID] ?: null;
  640.                             //Now let's find the winner customer record to the merged record for the next processing steps.
  641.                             if ($masterSfId) {
  642.                                 $master $customerRepo->findOneBy(['sf_id' => $masterSfId]);
  643.                             }
  644.                         }
  645.                         if ($merged && !$master) {
  646.                             // No record of a master customer in appsync db; check for a duplicate email.
  647.                             // We do this because when an email address is duplicated in SF, one of the possible
  648.                             // outcomes is the single appsync db record flips between the two SF accounts.
  649.                             $sfAccount $crud->query(
  650.                                 "SELECT Id, PersonEmail, MAS90_Account_ID__c FROM Account WHERE Id = '$masterSfId' ORDER BY LastModifiedDate DESC LIMIT 1"
  651.                             );
  652.                             if ($sfAccount) {
  653.                                 // We have found a master record in Salesforce that is not in the appsync db.
  654.                                 // Check if it's a dupe identifier; if so, we just need to update the appsync db
  655.                                 // to the correct master record and trigger a sync.
  656.                                 //
  657.                                 // In this case, the BC ID in the record should already be correct, as there can
  658.                                 // be no duplicate email address.
  659.                                 
  660.                                 if (((!$isBusinessAccount) && 
  661.                                     $customerEmail == $sfAccount[SFField::FIELD_PERSONAL_EMAIL])
  662.                                     || (($isBusinessAccount) && 
  663.                                     ($customerSageId == $sfAccount[SFField::FIELD_MAS90_ACC_ID]))
  664.                                 ) {
  665.                                     $logger->info(__METHOD__ ' SFCustomer duplicate email or business Sage ID, single record in appsync db - update appsync record and trigger sync: ' $sfLoser['Id']);
  666.                                     $customer->setSfId($masterSfId);
  667.                                     $comm->setStatus(Comm::STATUS_COMPLETE);
  668.                                     $entityManager->persist($comm);
  669.                                     $entityManager->flush();
  670.                                     $customer $customerRepo->find($customerId);
  671.                                     $salesForceCustomerConverter->exportCustomer($customer);
  672.                                     break;
  673.                                 }
  674.                             }
  675.                         }
  676.                         if ($merged && $master) {
  677.                             // Master record found in appsync db. Check if it's a duplicate email. If so, 
  678.                             // the orders in BC should ALREADY be attached to the correct customer account, as
  679.                             // customer email address is UNIQUE in BC. We don't want to delete the BC customer as 
  680.                             // the "winner" is the same as the "loser" in this case.
  681.                             if (((!$isBusinessAccount) && 
  682.                                 $customerEmail == $master->getEmailAddress())
  683.                                 || ($isBusinessAccount && 
  684.                                 ($customer->getSageId() == $master->getSageId()))
  685.                             ) {
  686.                                 $logger->info(__METHOD__ ' SFCustomer duplicate email or business Sage ID - only delete appsync record: ' $sfLoser['Id']);
  687.                                 $this->deleteAppsyncCustomer($customer$entityManager$logger);
  688.                                 $comm->setStatus(Comm::STATUS_COMPLETE);
  689.                                 $entityManager->persist($comm);
  690.                                 $entityManager->flush();
  691.                                 break;
  692.                             }
  693.                             // check for orders on the account
  694.                             $bcOrders $this->listBcOrdersByCustomerId($customerId$bigCommerceClient$entityManager$logger);
  695.                             $logger->info(__METHOD__ ' bcOrders: ' $this->encodeJson($bcOrders));
  696.                             if ($bcOrders) { // if orders:
  697.                                 if ($master->getBcId()) {
  698.                                     $newOrderCustomerId $master->getBcId();
  699.                                     $this->moveBcOrdersToCustomer($bcOrders$newOrderCustomerId$entityManager$logger$bigCommerceClient);
  700.                                 } 
  701.                             }
  702.                         }
  703.                         //Delete the customer record in BigCommerce
  704.                         $logger->info("SF merge loser, deleting BC ID: " $customer->getBcId());
  705.                         $bigCommerceClient->deleteCustomer($customer->getBcId());
  706.                         $this->deleteAppsyncCustomer($customer$entityManager$logger);
  707.                     }
  708.                     $comm->setStatus(Comm::STATUS_COMPLETE);
  709.                     $entityManager->persist($comm);
  710.                     $entityManager->flush();
  711.                 }
  712.             }
  713.         } catch (\Exception $e) {
  714.             $logger->error("Error - SalesforceController CustomerDelete" $e->getMessage());
  715.             $this->sendNotification(
  716.                 'App Error - SalesforceController CustomerDelete',
  717.                 str_replace("\u0000","",json_encode((array)$eJSON_PRETTY_PRINT))
  718.             );
  719.         }
  720.         $response = new Response();
  721.         return $response;
  722.     }
  723.     /**
  724.      * Receive Customer Updates From Salesforce
  725.      * @param Request $request
  726.      * @return Response
  727.      */
  728.     public function SalesforceCustomer(
  729.         Request $request
  730.         EntityManagerInterface $entityManager,
  731.         LoggerInterface $logger
  732.     ) {
  733.         try {
  734.             $logger->debug("Salesforce customer delete: " $this->encodeJson($request->getContent()));
  735.             $content $request->getContent();
  736.             $comm = new Comm();
  737.             $comm->setService(Comm::SERVICE_CUSTOMER);
  738.             $comm->setType(Comm::TYPE_SF_RECEIVE_HOOK);
  739.             $comm->setDtCreated((\DateTime::createFromFormat('Y-m-d H:i:s'date('Y-m-d  H:i:s'time()))));
  740.             $comm->setStatus(Comm::STATUS_NEW);
  741.             $comm->setRequest($this->encodeJson($request));
  742.             $comm->setContent($content);
  743.             $comm->setHttpStatus(Response::HTTP_OK);
  744.             $entityManager->persist($comm);
  745.             $entityManager->flush();
  746.         } catch (\Exception $e) {
  747.             $logger->error("Error - SalesforceController SalesforceCustomer" $e->getMessage());
  748.         }
  749.         $response = new Response();
  750.         $response->setStatusCode(204);
  751.         return $response;
  752.     }
  753.     private function encodeJson($valueIn$jsonOptions 0) {
  754.         if (is_object($valueIn)) {
  755.             return str_replace("\u0000","",str_replace("\u0000*\u0000","",json_encode((array)$valueIn$jsonOptions)));
  756.         } else if (is_array($valueIn) || is_iterable($valueIn)) {
  757.             return json_encode((array)$valueIn$jsonOptions);
  758.         }
  759.         return json_encode($valueIn$jsonOptions);
  760.     }
  761. }