Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/sale/lib/exchange/ |
Upload File : |
<?php namespace Bitrix\Sale\Exchange; use Bitrix\Sale\Exchange\Entity\OrderImport; use Bitrix\Sale\Exchange\Entity\SubordinateSale\EntityImportFactory; use Bitrix\Sale\Exchange\OneC\DocumentBase; use Bitrix\Sale\Exchange\OneC\DocumentType; use Bitrix\Sale\Exchange\OneC\PaymentCardDocument; use Bitrix\Sale\Exchange\OneC\SubordinateSale\ConverterFactory; use Bitrix\Sale\Exchange\OneC\SubordinateSale\CriterionShipment; use Bitrix\Sale\Exchange\OneC\SubordinateSale\DocumentFactory; use Bitrix\Sale\Exchange\OneC\SubordinateSale\ShipmentDocument; use Bitrix\Sale\Order; use Bitrix\Sale\Payment; use Bitrix\Sale\Result; use Bitrix\Sale\Shipment; final class ImportOneCSubordinateSale extends ImportOneCPackage { public static function configuration() { ManagerImport::registerInstance(static::getShipmentEntityTypeId(), OneC\ImportSettings::getCurrent(), new OneC\CollisionShipment(), new CriterionShipment()); parent::configuration(); } /** * @param DocumentBase[] $documents * @return \Bitrix\Sale\Result */ protected function convert(array $documents) { $documentOrder = $this->getDocumentByTypeId(EntityType::ORDER, $documents); if($documentOrder instanceof OneC\OrderDocument) { $fieldsOrder = $documentOrder->getFieldValues(); $itemsOrder = $this->getProductsItems($fieldsOrder); if(is_array($fieldsOrder['SUBORDINATES'])) { foreach ($fieldsOrder['SUBORDINATES'] as $subordinateDocumentFields) { $typeId = $this->resolveSubordinateDocumentTypeId($subordinateDocumentFields); if($typeId == static::getShipmentEntityTypeId()) { $subordinateDocumentItems = array(); $itemsSubordinate = $this->getProductsItems($subordinateDocumentFields); foreach ($itemsSubordinate as $itemSubordinate) { $xmlId = key($itemSubordinate); if($xmlId == self::DELIVERY_SERVICE_XMLID) { $itemSubordinate[$xmlId]['TYPE'] = ImportBase::ITEM_SERVICE; $subordinateDocumentItems[] = $itemSubordinate; } else { $item = $this->getItemByParam($xmlId, $itemsOrder); if($item !== null) { $item[$xmlId]['QUANTITY'] = $itemSubordinate[$xmlId]['QUANTITY']; $subordinateDocumentItems[] = $item; } } } unset($subordinateDocumentFields['ITEMS']); unset($subordinateDocumentFields['ITEMS_FIELDS']); if(count($subordinateDocumentItems)>0) { $subordinateDocumentFields['ITEMS'] = $subordinateDocumentItems; } } $document = OneC\DocumentImportFactory::create($typeId); $document->setFields($subordinateDocumentFields); $documents[] = $document; } $documentOrder->setField('SUBORDINATES', ''); } //region Presset - генерируем фэйковую отгрузку /* * генерируем фэйковую отгрузку, если выполнены условия * 1 обмен с новым модулем от 1С, * 2 отгрузки не переданы в подчиненных документах * 3 все отгрузки по заказу в БУС в статусе не отгружено * 4 и от 1С в табличной части заказа передана ORDER_DELIVERY * */ if(!$this->hasDocumentByTypeId(static::getShipmentEntityTypeId(), $documents)) { if($this->deliveryServiceExists($itemsOrder)) { //$deliveryItem $entityOrder = $this->convertDocument($documentOrder); if($entityOrder->getFieldValues()['TRAITS']['ID']>0) { self::load($entityOrder, ['ID'=>$entityOrder->getFieldValues()['TRAITS']['ID']]); /** @var Order $order */ $order = $entityOrder->getEntity(); if(!$order->isShipped()) { $shipmentList = []; $shipmentIsShipped = false; /** @var Shipment $shipment */ foreach ($order->getShipmentCollection() as $shipment) { if($shipment->isShipped()) { $shipmentIsShipped = true; break; } if(!$shipment->isSystem()) { $shipmentList[] = $shipment->getFieldValues(); } } if(!$shipmentIsShipped) { if(count($shipmentList)>0) { //системная и реальная отгрузка $externalId = current($shipmentList)['ID_1C']; $shipmentFields['ID_1C'] = $externalId == ''? $documentOrder->getField('ID_1C'):$externalId; $shipmentFields['ID'] = current($shipmentList)['ID']; } else { //только системная отгрузка $shipmentFields['ID_1C'] = $documentOrder->getField('ID_1C'); } // колличество и вся табличная часть всегда береться из заказа т.к. все отгрузки вводятся в 1С и на сайте вообще не может измениться что-то в отгрузке. (требования 1С) $shipmentFields['ITEMS'] = $itemsOrder; $documentShipment = new ShipmentDocument(); $documentShipment->setFields($shipmentFields); $documents[] = $documentShipment; } } } } } //endregion //region - оплаты // от 1С может приходить только оплаченные оплаты, шаблоны приходить не могут. // Удаляем все не оплаченные оплаты из коллекции документов оплат $documents = $this->deletePaymentDocumentNotPaid($documents); /** @var OrderImport $entityOrder */ $entityOrder = $this->convertDocument($documentOrder); if($entityOrder->getFieldValues()['TRAITS']['ID']>0) { self::load($entityOrder, ['ID'=>$entityOrder->getFieldValues()['TRAITS']['ID']]); /** @var Order $order */ $order = $entityOrder->getEntity(); if(!empty($order)) { $hasPayment = $order->isPaid() || $this->orderPartiallyIsPaid($order); if($this->hasPaymentDocuments($documents)) { // оплаченных оплат - нет if(!$hasPayment) { if($order->getPrice() <= $this->getPaymentDocumentsPaidSum($documents)) { //region 2. Из 1С приходит полная оплата - удаляем шаблоны в БУС, заменяем на оплату из 1С //endregion } } // частичная оплата заказа коллекцией документов оплат $paymentDocumentsPaidSum = $this->getPaymentDocumentsPaidSum($documents); if($order->getPrice() > $paymentDocumentsPaidSum) { //region 3. Из 1С приходит частичная оплата - пытаемся сверить по сумме и по типу, // если подходит - удаляем шаблон с такой же суммой и типом, создаем оплату из 1С. // Остальные шаблоны оплаты не трогаем. // Если по выбранным критериям (сумма + тип) выбираются 2 и более шаблонов выбираем последнюю оплату по ID //$r = $this->documentPaymentReplaceId($order, $documents); //TODO: оплата должна удаляться через срзданный документ удаления оплаты. $r = $this->deletePaymentToReplace($order, $documents); if($r->isSuccess()) { $entityOrder->save(); } if($r->getData()['IS_REPLACE'] === true) { static::setConfig(static::DELETE_IF_NOT_FOUND_RELATED_PAYMENT_DOCUMENT, false); } else { //3.1. Если по сумме ничего не находим. //- удаляем все шаблоны //- если есть оплаченная оплата в БУС, которая не пришла из 1С – коллизия //-обновляем те оплаты информация по которым пришла от 1С //-создаем частичную оплату от 1С //-создаем шаблон оплаты согласно настройкам интеграции на оставшуюся сумму $documentPayment = new PaymentCardDocument(); $documentPayment->setFields([ 'ID_1C'=>$documentOrder->getField('ID_1C'), 'AMOUNT'=>abs($order->getPrice() - $paymentDocumentsPaidSum) ]); $documents[] = $documentPayment; } //endregion } } else { //region 1. Из 1С не приходит оплат - в БУС шаблоны оплат не удаляем if(!$hasPayment) { static::setConfig(static::DELETE_IF_NOT_FOUND_RELATED_PAYMENT_DOCUMENT, false); } //endregion } } } //TODO: доделать удаления оплат из списка документов оплат к импорту. И создания шаблона на всю оставшуюся сумму после импорта частичной оплаты от 1С //endregion } return parent::convert($documents); } /** * @param DocumentBase[] $documents * @return array */ protected function deletePaymentDocumentNotPaid(array $documents) { $result=[]; foreach ($documents as $document) { if($this->isPaymentDocument($document)) { if($this->documentIsPaid($document)) { $result[] = $document; } } else { $result[] = $document; } } return $result; } /** * @param DocumentBase $document * @return bool */ protected function documentIsPaid(DocumentBase $document) { return ($document->getField('REK_VALUES')['1C_PAYED'] == 'Y'); } /** * @param DocumentBase $document * @return bool */ protected function isPaymentDocument(DocumentBase $document) { return ($document->getTypeId() == static::getPaymentCardEntityTypeId() || $document->getTypeId() == static::getPaymentCashLessEntityTypeId() || $document->getTypeId() == static::getPaymentCashEntityTypeId()); } protected function documentPaymentReplaceId(Order $order, $documents) { $result = new Result(); $paymentCollection = $order->getPaymentCollection(); $paymentIsReplace = false; /** @var Payment $payment */ foreach($paymentCollection as $payment) { if(!$payment->isPaid()) { /** @var DocumentBase $document */ foreach($this->getPaymentDocuments($documents) as $document) { if( $payment->getSum() == (float)$document->getField('AMOUNT') && $this->resolveEntityTypeId($payment) == DocumentType::resolveID($document->getField('OPERATION')) ) { $document->setField('ID', $payment->getId()); $paymentIsReplace = true; } } } } $result->setData(['IS_REPLACE'=>$paymentIsReplace]); return $result; } /** * @param Order $order * @param DocumentBase[] $documents */ protected function deletePaymentToReplace(Order $order, $documents) { $result = new Result(); $paymentCollection = $order->getPaymentCollection(); $paymentIsReplace = false; $list = []; foreach ($documents as $document) { if($this->isPaymentDocument($document)) { $list[] = [ 'AMOUNT'=>(float)$document->getField('AMOUNT'), 'OPERATION'=>DocumentType::resolveID($document->getField('OPERATION')) ]; } } if(count($list)>0) { /** @var Payment $payment */ foreach($paymentCollection as $payment) { if(!$payment->isPaid()) { foreach($list as $k=>$documentPayment) { //echo $this->resolveEntityTypeId($payment); if( $payment->getSum() == $documentPayment['AMOUNT'] && $this->resolveEntityTypeId($payment) == $documentPayment['OPERATION'] ) { $r = $this->paymentDelete($payment); if(!$r->isSuccess()) { $result->addErrors($r->getErrors()); } else { $paymentIsReplace = true; } unset($list[$k]); } } } } } if($result->isSuccess() && $paymentIsReplace) $result->setData(['IS_REPLACE'=>true]); return $result; } /** * @param DocumentBase[] $documents * @return bool */ protected function hasPaymentDocuments(array $documents) { return ($this->hasDocumentByTypeId(static::getPaymentCardEntityTypeId(), $documents) || $this->hasDocumentByTypeId(static::getPaymentCashLessEntityTypeId(), $documents) || $this->hasDocumentByTypeId(static::getPaymentCashEntityTypeId(), $documents)); } /** * @param DocumentBase[] $documents * @return array */ protected function getPaymentDocuments($documents) { $list = []; foreach ($documents as $document) { if($this->isPaymentDocument($document)) { $list[] = $document; } } return $list; } /** * @param DocumentBase[] $documents * @return float|int */ protected function getPaymentDocumentsPaidSum($documents) { $sum = 0; /** @var DocumentBase $document */ foreach ($this->getPaymentDocuments($documents) as $document) { //echo '<pre>';print_r($document->getFieldValues()); if($this->documentIsPaid($document)) { $sum += (float)$document->getField('AMOUNT'); } } return $sum; } protected function orderPartiallyIsPaid(Order $order) { $paymentCollection = $order->getPaymentCollection(); if(count($paymentCollection)>0) { /** @var Payment $payment */ foreach ($paymentCollection as $payment) { if($payment->isPaid()) return true; } } return false; } /** * @param array $fields * @return int */ protected function resolveSubordinateDocumentTypeId(array $fields) { $typeId = EntityType::UNDEFINED; if(isset($fields['OPERATION'])) { $typeId = EntityType::resolveID($fields['OPERATION']); } return $typeId; } /** * @param $xmlId * @param array $items * @param array|null $params * @return mixed|null */ protected function getItemByParam($key, array $items, array $params=null) { foreach ($items as $item) { if(array_key_exists($key, $item)) { return $item; } } return null; } /** * @param $typeId * @return IConverter */ protected function converterFactoryCreate($typeId) { return ConverterFactory::create($typeId); } /** * @param $typeId * @return DocumentBase */ protected function documentFactoryCreate($typeId) { return DocumentFactory::create($typeId); } /** * @param $typeId * @return ImportBase */ protected function entityFactoryCreate($typeId) { return EntityImportFactory::create($typeId); } }