Advertisement
Guest User

Untitled

a guest
Jul 18th, 2018
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 16.10 KB | None | 0 0
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\C1\Connector;
  4.  
  5. use App\Application\Exceptions\Interfaces\ExceptionManagerAwareInterface;
  6. use App\Application\Exceptions\Manager\ExceptionManagerAwareTrait;
  7. use App\C1\Connector\Exceptions\ErrorGetBalance;
  8. use App\Finance\Balance\Exceptions\BalanceException;
  9. use App\Finance\Balance\Interfaces\Status;
  10. use App\Finance\Balance\Manager\BalanceManager;
  11. use App\Finance\Balance\Manager\Change;
  12. use App\Finance\Balance\Manager\ChangeResult;
  13. use App\Finance\Balance\Operation\Balance;
  14. use App\Finance\Balance\Operation\Block;
  15. use App\Finance\Balance\Status\Canceled;
  16. use App\Finance\Balance\Status\Executed;
  17. use App\InterServices\Billing\Data\BlockDepositParams;
  18. use App\InterServices\Billing\Data\BlockDepositResult;
  19. use App\InterServices\Billing\Data\GetBalanceParams;
  20.  
  21. /**
  22.  * Коннектор 1С.
  23.  * Один из центральных классов для работы с 1С сервером
  24.  */
  25. class Connector implements ExceptionManagerAwareInterface
  26. {
  27.     use ExceptionManagerAwareTrait;
  28.  
  29.     /**
  30.      * Клиент для связи с 1С сервером
  31.      *
  32.      * @var ApiClient
  33.      */
  34.     protected $apiClient;
  35.  
  36.     /**
  37.      * Карта исключений для связи их со статусами операций
  38.      *
  39.      * @var ExceptionMapper
  40.      */
  41.     protected $exceptionMapper;
  42.  
  43.     /**
  44.      * Конструктор класса
  45.      *
  46.      * @param ApiClient $apiClient
  47.      * @param ExceptionMapper $exceptionMapper
  48.      */
  49.     public function __construct(ApiClient $apiClient, ExceptionMapper $exceptionMapper)
  50.     {
  51.         $this->apiClient = $apiClient;
  52.         $this->exceptionMapper = $exceptionMapper;
  53.     }
  54.  
  55.     /**
  56.      * Получает баланс от 1С.
  57.      * Текущий баланс не сравнивает
  58.      *
  59.      * @param string $accountNumber
  60.      * @param bool $withNds
  61.      * @throws ErrorGetBalance
  62.      * @return array
  63.      */
  64.     public function getBalance(string $accountNumber, bool $withNds): Balance
  65.     {
  66.         try {
  67.             $result = $this->apiClient->getBalance($accountNumber, $withNds);
  68.             return $result;
  69.         } catch (\Throwable $e) {
  70.             $this->exceptionManager->log($e);
  71.             $this->logger->debug('Error get balance', [
  72.                 'accountNumber' => $accountNumber,
  73.                 'withNds' => $withNds
  74.             ]);
  75.  
  76.             throw new ErrorGetBalance($accountNumber, $withNds, $e);
  77.         }
  78.     }
  79.  
  80.  
  81.     /**
  82.      * Отсылает операцию в 1С и возвращает ответ от 1с
  83.      *
  84.      * @param Change $change
  85.      * @return array
  86.      */
  87.     public function sendOperation(Change $change): Status
  88.     {
  89.         $result1C = $this->apiClient->operation($change);
  90.         return $result1C;
  91.  
  92.     }
  93.  
  94. }
  95.  
  96.  
  97. class BalanceGetter implements ExceptionManagerAwareInterface
  98. {
  99.     use ExceptionManagerAwareTrait;
  100.  
  101.     /**
  102.      * Коннектор 1С
  103.      *
  104.      * @varApp\Connector1C\Connector
  105.      */
  106.     protected $connector;
  107.  
  108.     /** @var  BalanceManager $balanceManager
  109.      * */
  110.     protected $balanceManager;
  111.  
  112.     /**
  113.      * Конструктор класса
  114.      *
  115.      * @param Connector $connector
  116.      * @param BalanceManager $balanceManager
  117.      */
  118.     public function __construct(Connector $connector, BalanceManager $balanceManager)
  119.     {
  120.         $this->connector = $connector;
  121.         $this->balanceManager = $balanceManager;
  122.     }
  123.  
  124.     /**
  125.      * Возвращает текущий баланс счета
  126.      *
  127.      * @param GetBalanceParams $params
  128.      * @return GetBalanceResult
  129.      */
  130.     public function get(GetBalanceParams $params): Balance
  131.     {
  132.         $balance = $this->compareBalance($params->account, $params->nds);
  133.  
  134.         $result = new Balance();
  135.         $result->account = $params->account;
  136.         $result->nds = $params->nds;
  137.  
  138.         $result->available = $balance->getAvailable();
  139.         $result->blocked = $balance->getBlocked();
  140.         $result->total = $balance->getAvailable() + $balance->getBlocked();
  141.  
  142.         return $result;
  143.     }
  144.  
  145.     /**
  146.      * Получает баланс от 1С и сравнивает его с текущим балансом.
  147.      * Если не совпадения, то это сваливается в сислог и все об этом узнают
  148.      *
  149.      * @param string $accountNumber
  150.      * @param bool $withNds
  151.      * @return Balance
  152.      */
  153.     public function compareBalance(string $accountNumber, bool $withNds): Balance
  154.     {
  155.         try {
  156.             $balance = $this->balanceManager->getBalance($accountNumber, $withNds);
  157.             $balance1cArray = $this->connector->getBalance($accountNumber, $withNds);
  158.             $balance1c =  new Balance($balance1cArray['available'], $balance1cArray['blocked']);
  159.             if (($balance->getAvailable() != $balance1c->getAvailable()) || ($balance->getBlocked() != $balance1c->getBlocked())) {
  160.                 $this->exceptionManager->getLogger()->error('Balances not equals', [
  161.                     'account' => $accountNumber,
  162.                     'withNds' => $withNds,
  163.                     'available' => $balance->getAvailable(),
  164.                     'blocked' => $balance->getBlocked(),
  165.                     'available1c' => $balance1c->getAvailable(),
  166.                     'blocked1c' => $balance1c->getBlocked()
  167.                 ]);
  168.             }
  169.         } catch (\Throwable $e) {
  170.             $this->exceptionManager->log($e);
  171.             $this->exceptionManager->getLogger()->error('Error compare balances', [
  172.                 'account' => $accountNumber,
  173.                 'withNds' => $withNds
  174.             ]);
  175.         }
  176.  
  177.         return $balance;
  178.     }
  179.  
  180.  
  181.  
  182.  
  183.  
  184. }
  185.  
  186. /**
  187.  * Групповое исполнение операций
  188.  */
  189. class ExecuteOperations implements ExceptionManagerAwareInterface
  190. {
  191.     use ExceptionManagerAwareTrait;
  192.  
  193.     /**
  194.      * Максимальное время исполнения скрипта в секундах
  195.      *
  196.      * @var integer
  197.      */
  198.     const TIME_LIMIT = 300;
  199.  
  200.     /**
  201.      * Коннектор 1С
  202.      *
  203.      * @varApp\Connector1C\Connector
  204.      */
  205.     protected $connector;
  206.  
  207.     /**
  208.      *
  209.      * @var BalanceGetter
  210.      */
  211.     protected $balanceGetter;
  212.  
  213.     /**
  214.      * Генератор - обертка над транзакциями БД
  215.      *
  216.      * @var App\Balance\Manager\TransIterator
  217.      */
  218.     protected $transIterator;
  219.  
  220.     /**
  221.      * Конструктор класса
  222.      *
  223.      * @param Connector $connector
  224.      * @param \App\InterServices\Billing\BalanceGetter $balanceGetter
  225.      * @param TransIterator $transIterator
  226.      */
  227.     public function __construct(Connector $connector, \App\InterServices\Billing\BalanceGetter $balanceGetter, TransIterator $transIterator)
  228.     {
  229.         $this->connector = $connector;
  230.         $this->balanceGetter = $balanceGetter;
  231.         $this->transIterator = $transIterator;
  232.     }
  233.  
  234.     /**
  235.      * Выполнение операций
  236.      *
  237.      * @param Operation[] ...$operations
  238.      * @return executeOperationResult
  239.      */
  240.     public function execute(Operation ...$operations): executeOperationResult
  241.     {
  242.         $result = new executeOperationResult();
  243.         $result->status = $result::FAILURE;
  244.  
  245.         $this->logger->info('Execute method start');
  246.  
  247.         try {
  248.             set_time_limit(self::TIME_LIMIT);
  249.             ignore_user_abort(true);
  250.  
  251.             if (empty($operations)) {
  252.                 throw new EmptyOperationsArray();
  253.             }
  254.  
  255.             $changes = $this->initOperations(...$operations);
  256.             $changeResults = $this->addTransactions(...$changes);
  257.             $this->sendRequestTo1C(...$changes);
  258.             $this->setStatusForOperations(new Executed(), ...$changeResults);
  259.  
  260.             $result->status = $result::SUCCESS;
  261.             $result->balances = $this->getBalances(...$operations);
  262.             $this->logger->info('Execute method end success');
  263.         } catch (\Throwable $e) {
  264.             if (!empty($changeResults)) {
  265.                 $this->setStatusForOperations(new Canceled(), ...$changeResults);
  266.             }
  267.  
  268.             $result->message = $this->exceptionManager->log($e);
  269.             $this->logger->debug('Execute method end with errors: ' . $result->message);
  270.         } finally {
  271.             ignore_user_abort(false);
  272.         }
  273.  
  274.         return $result;
  275.     }
  276.  
  277.     /**
  278.      *
  279.      * @param Operation[] ...$operations
  280.      * @return array
  281.      */
  282.     protected function initOperations(Operation ...$operations): array
  283.     {
  284.         $changes = [];
  285.  
  286.         foreach ($operations as $operation) {
  287.             $currentOperation = null;
  288.  
  289.             /**
  290.              *
  291.              * @var Operation $operation
  292.              */
  293.             switch ($operation->type) {
  294.                 case OperationInterface::BLOCK:
  295.                     $currentOperation = new Block($operation->sum);
  296.                     break;
  297.  
  298.                 case OperationInterface::DEBIT:
  299.                     $currentOperation = new Debit($operation->sum);
  300.                     break;
  301.  
  302.                 case OperationInterface::UNBLOCK:
  303.                     $currentOperation = new Unblock($operation->sum);
  304.                     break;
  305.  
  306.                 default:
  307.                     throw new UnknownOperation($operation->type);
  308.             }
  309.  
  310.             $changes[] = new Change($operation->account, $operation->nds, $operation->basis, $currentOperation);
  311.         }
  312.  
  313.         return $changes;
  314.     }
  315.  
  316.     /**
  317.      *
  318.      * @param Operation[] ...$operations
  319.      * @return array
  320.      */
  321.     protected function getBalances(Operation ...$operations): array
  322.     {
  323.         $balances = [];
  324.  
  325.         foreach ($operations as $operation) {
  326.             $getBalanceParams = new GetBalanceParams();
  327.             $getBalanceParams->nds = $operation->getNds();
  328.             $getBalanceParams->account = $operation->getAccount();
  329.             $balanceData = $this->balanceGetter->get($getBalanceParams);
  330.  
  331.             $balances[] = $balanceData;
  332.         }
  333.  
  334.         return $balances;
  335.     }
  336.  
  337.     /**
  338.      *
  339.      * @param Change[] ...$changes
  340.      * @return array
  341.      * @throws \Throwable
  342.      */
  343.     protected function addTransactions(Change ...$changes): array
  344.     {
  345.         $this->logger->info('AddTransactions method start');
  346.         $changeResults = [];
  347.  
  348.         $items = $this->transIterator->get($changes);
  349.  
  350.         try {
  351.             foreach ($items as $change) {
  352.                 $changeResults[] = $this->connector->addOperation($change);
  353.             }
  354.         } catch (\Throwable $e) {
  355.             $items->throw($e);
  356.         }
  357.  
  358.         $this->logger->info('AddTransactions method end success');
  359.         return $changeResults;
  360.     }
  361.  
  362.     /**
  363.      *
  364.      * @param Status $status
  365.      * @param ChangeResult[] ...$changeResults
  366.      * @throws \Throwable
  367.      */
  368.     protected function setStatusForOperations(Status $status, ChangeResult ...$changeResults)
  369.     {
  370.         $this->logger->info('SetStatusForOperations method start with status: ' . $status->getStatus());
  371.         $items = $this->transIterator->get($changeResults);
  372.         try {
  373.             foreach ($items as $item) {
  374.                 $item->setStatus($status);
  375.             }
  376.         } catch (\Throwable $e) {
  377.             $items->throw($e);
  378.         }
  379.  
  380.         $this->logger->info('SetStatusForOperations method end success');
  381.     }
  382.  
  383.     /**
  384.      *
  385.      * @param Change[] ...$changes
  386.      * @throws \Throwable
  387.      */
  388.     protected function sendRequestTo1C(Change ...$changes)
  389.     {
  390.         $this->logger->info('SendRequestTo1C method start');
  391.  
  392.         try {
  393.             foreach ($changes as $change) {
  394.                 $statusObject = $this->sendOperation($change);
  395.                 $status = $statusObject->getStatus();
  396.  
  397.                 if ($status != Status::EXECUTED) {
  398.                     throw new OperationNotExecuted($status);
  399.                 }
  400.             }
  401.  
  402.             $this->logger->info('SendRequestTo1C method end success');
  403.         } catch (\Throwable $e) {
  404.             $this->logger->info('SendRequestTo1C method end with errors');
  405.             throw $e;
  406.         }
  407.     }
  408.  
  409.     /**
  410.      * Добавляет новую операцию и отсылает ее в 1С
  411.      *
  412.      * @param Change $change
  413.      * @return Status
  414.      */
  415.     public function operation(Change $change): Status
  416.     {
  417.         $changeResult = $this->addOperation($change);
  418.         $result = $this->sendOperation($change);
  419.         $changeResult->setStatus($result);
  420.         return $result;
  421.     }
  422.  
  423.  
  424.     /**
  425.      * Отсылает операцию в 1С и возвращает статус операции
  426.      *
  427.      * @param Change $change
  428.      * @return Status
  429.      */
  430.     public function sendOperation(Change $change): Status
  431.     {
  432.         try {
  433.             $result1C = $this->connector->sendOperation($change);
  434.             if ($result1C['status'] === 'executed') {
  435.                 $result = new Executed();
  436.             } else {
  437.                 $result = new Canceled();
  438.             }
  439.         } catch (\Throwable $e) {
  440.             $this->exceptionManager->log($e);
  441.             $result = $this->exceptionMapper->getStatus($e);
  442.         }
  443.  
  444.         return $result;
  445.     }
  446.  
  447.     /**
  448.      * Добавляет новую операцию.
  449.      * Если недостаточно денег для этой операции, то проверяет баланс в 1С
  450.      *
  451.      * @param Change $change
  452.      * @throws BalanceException
  453.      * @return ChangeResult
  454.      */
  455.     public function addOperation(Change $change): ChangeResult
  456.     {
  457.         $logger = $this->logger;
  458.  
  459.         try {
  460.              //@toDo Вот тут осталась зависимость от менеджера, которую я выпилил из конструктора. Возможно, решением проблемы может стать переименоваине класса balanceGetter во что-то другое и добавление туда проброса этого метода
  461.             $result = $this->balanceManager->add($change);
  462.         } catch (BalanceException $e) {
  463.             $this->exceptionManager->log($e);
  464.             $logger->critical('Not enough money', $change->getContext());
  465.             $this->balanceGetter->compareBalance($change->getAccountNumber(), $change->getWithNds());
  466.             throw $e;
  467.         }
  468.  
  469.         return $result;
  470.     }
  471.  
  472. }
  473.  
  474.  
  475. /**
  476.  * Блокировка денег на счету
  477.  */
  478. class BlockDeposit implements ExceptionManagerAwareInterface
  479. {
  480.     use ExceptionManagerAwareTrait;
  481.  
  482.     /**
  483.      * Коннектор 1С
  484.      *
  485.      * @var ExecuteOperations
  486.      */
  487.     protected $executeOperations;
  488.  
  489.     /**
  490.      * Конструктор класса
  491.      *
  492.      * @param Connector $executeOperations
  493.      */
  494.     public function __construct(ExecuteOperations $executeOperations)
  495.     {
  496.         $this->executeOperations = $executeOperations;
  497.     }
  498.  
  499.     /**
  500.      * Блокировка средств
  501.      *
  502.      * @param BlockDepositParams $params
  503.      * @return BlockDepositResult
  504.      */
  505.     public function block(BlockDepositParams $params): BlockDepositResult
  506.     {
  507.         $result = new BlockDepositResult();
  508.         $this->logger->debug('Block method start');
  509.  
  510.         try {
  511.             $blockOperation = new Block($params->sum);
  512.             $change = new Change($params->account, $params->nds, $params->basis, $blockOperation);
  513.             $status = $this->executeOperations->operation($change);
  514.             if ($status instanceof Executed) {
  515.                 $result->status = $result::SUCCESS;
  516.             } else {
  517.                 $result->status = $result::FAILURE;
  518.                 $result->message = $status->getStatus();
  519.             }
  520.         } catch (\Throwable $e) {
  521.             $result->status = $result::FAILURE;
  522.             $result->message = $this->exceptionManager->log($e);
  523.         }
  524.  
  525.         $this->logger->debug('Block method end. Status:' . $result->status);
  526.         return $result;
  527.     }
  528. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement