Files
crm.clientright.ru/modules/SPCMLConnector/CMLParser200.php
Fedor ac7467f0b4 Major CRM updates: AI Assistant, Court Status API, S3 integration improvements, and extensive file storage system
- Added comprehensive AI Assistant system (aiassist/ directory):
  * Vector search and embedding capabilities
  * Typebot proxy integration
  * Elastic search functionality
  * Message classification and chat history
  * MCP proxy for external integrations

- Implemented Court Status API (GetCourtStatus.php):
  * Real-time court document status checking
  * Integration with external court systems
  * Comprehensive error handling and logging

- Enhanced S3 integration:
  * Improved file backup system with metadata
  * Batch processing capabilities
  * Enhanced error logging and recovery
  * Copy operations with URL fixing

- Added Telegram contact creation API
- Improved error logging across all modules
- Enhanced callback system for AI responses
- Extensive backup file storage with timestamps
- Updated documentation and README files

- File storage improvements:
  * Thousands of backup files with proper metadata
  * Fix operations for broken file references
  * Project-specific backup and recovery systems
  * Comprehensive file integrity checking

Total: 26,461+ files added/modified including AWS SDK, vendor dependencies, and extensive backup system.
2025-10-16 11:17:21 +03:00

383 lines
16 KiB
PHP

<?php
/**
* Parser for protocol version 2.00-2.06
*/
class CMLParser200 extends AbstractCMLParser {
public function parseImport($importXml) {
$this->checkMandatoryChildElement($importXml, "Каталог", "Not catalog in import.xml!");
return $this->initilizateCatalog($importXml->Каталог);
}
public function parseOffer($offerXml) {
$this->checkMandatoryChildElement($offerXml, "ПакетПредложений", "Not package in offers.xml!");
return $this->initilizatePackage($offerXml->ПакетПредложений);
}
public function parseOrders($ordersXml) {
$cmlSalesOrders = array();
foreach($ordersXml->Документ as $xmlOrder) {
$number = $this->getMandatoryChildContent($xmlOrder, 'Номер', 'Not document number in orders.xml');
$oneEsidentifier = $this->getMandatoryChildContent($xmlOrder, 'Ид', 'Not document id in orders.xml! Document number - ' . $number);
$currency = $this->getMandatoryChildContent($xmlOrder, 'Валюта', 'Not document currency in orders.xml! Document number - ' . $number);
$salesOrder = new CmlSalesOrder($number, $oneEsidentifier, $currency);
$salesOrder = $this->getDocumentAccount($salesOrder,$xmlOrder);
$salesOrder = $this->initilizateOrderInventories($salesOrder, $xmlOrder);
$salesOrder = $this->initilizateOrderProps($salesOrder, $xmlOrder);
$cmlSalesOrders[] = $salesOrder;
}
return $cmlSalesOrders;
}
/**
* Initilizate new CmlCatalog by getted $catalog.
* @param SimpleXMLElement $catalog
* @return CmlCatalog
*/
protected function initilizateCatalog($catalog) {
/* Get catalog mandatory fields */
$catalogName = $this->getMandatoryChildContent($catalog, 'Наименование', 'Not catalog name in import.xml');
$catalogName = $this->filter($catalogName);
$oneEsIdentifier = $this->getMandatoryChildContent($catalog, 'Ид', 'Not catalog identificator in import.xml');
$cmlCatalog = new CmlCatalog($catalogName, $oneEsIdentifier);
$this->checkMandatoryChildElement($catalog, 'Товары', 'Not products in import.xml');
$cmlCatalog = $this->initilizateCatalogInventories($cmlCatalog, $catalog->Товары);
return $cmlCatalog;
}
/**
* Initilizate catalog products and services and return CmlCatalog.
* @param CmlCatalog $cmlCatalog
* @param SimpleXMLElement $catalogInventories
* return CmlCatalog
*/
protected function initilizateCatalogInventories($cmlCatalog, $catalogInventories) {
foreach($catalogInventories->Товар as $importInventory) {
if($this->isProduct($importInventory)) {
$inventory = new CmlProduct();
$inventory = $this->initilizateCatalogInventory($importInventory, $inventory);
$cmlCatalog->addProduct($inventory);
} else {
$inventory = new CmlService();
$inventory = $this->initilizateCatalogInventory($importInventory, $inventory);
$cmlCatalog->addService($inventory);
}
}
return $cmlCatalog;
}
/**
* Return AbstractProduct by $importProduct
* @param SimpleXMLElement $xmlInventoryDescription
* @param CmlProduct|CmlService $inventory
* @return AbstractProduct
*/
protected function initilizateCatalogInventory($xmlInventoryDescription, $inventory) {
$name = $this->getMandatoryChildContent($xmlInventoryDescription, 'Наименование',
'Not product name in import.xml');
$oneEsIdentifier = $this->getMandatoryChildContent($xmlInventoryDescription, 'Ид',
'Not product identificator in import.xml');
$unitName = '';
if($this->isChildExists($xmlInventoryDescription, 'БазоваяЕдиница')) {
$unitName = $this->getBasicUnitFromXml($xmlInventoryDescription->БазоваяЕдиница);
}
$article = $this->getChildContent($xmlInventoryDescription, 'Артикул');
$NDS = $this->getTaxRate($xmlInventoryDescription);
/* REST API broke on special symbols */
$name = $this->filter($name);
$article = $this->filter($article);
$inventory->catalogInitilizate($oneEsIdentifier, $name, $article, $unitName, $NDS);
return $inventory;
}
/**
* Return tax rate. If no tax - return 0.
* @param SimpleXMLElement $importProduct
* @return int
*/
protected function getTaxRate($importProduct) {
if($this->isChildExists($importProduct, 'СтавкиНалогов')) {
$rates = $importProduct->СтавкиНалогов;
/* Search rate named NDS */
foreach($rates->СтавкаНалога as $rate) {
$rateName = $this->getChildContent($rate, 'Наименование');
$rateValue = $this->getChildContent($rate, 'Ставка');
/* If tax rate not NULL */
if($rateName == 'НДС' && $rateValue != 'Без налога' && $rateValue != NULL) {
return $rateValue;
}
}
}
return 0;
}
/**
* Initilizate prices, count and currencies of all inventories.
* @param SimpleXMLElement $package
* @return \CmlCatalog
*/
protected function initilizatePackage($package) {
$oneEsIdentifier = $this->getMandatoryChildContent($package, 'Ид', 'Not id in offers!');
$name = $this->getMandatoryChildContent($package, 'Наименование', 'Not name in offers!');
$name = $this->filter($name);
$cmlCatalog = new CmlCatalog($name, $oneEsIdentifier);
/* Get package currency */
$packageCurrency = $this->getPackageCurrency($package);
$cmlCatalog->setCurrency($packageCurrency);
/* Initilizate products and services */
$this->checkMandatoryChildElement($package, "Предложения", "Not offers in offers.xml!");
$cmlCatalog = $this->initilizatePackageInventories($package->Предложения, $cmlCatalog);
return $cmlCatalog;
}
/**
* Return currency from first price type.
* @param SimpleXMLElement $package
* @return String
*/
protected function getPackageCurrency($package) {
$this->checkMandatoryChildElement($package, "ТипыЦен", "Not price type in offers.xml!");
$priceTypes = $package->ТипыЦен;
/* Get first price type */
$this->checkMandatoryChildElement($priceTypes, "ТипЦены", "Not price type in offers.xml!");
$priceType = $priceTypes->ТипЦены;
$currency = $this->getMandatoryChildContent($priceType, "Валюта", "Not price type in offers.xml!");
return $currency;
}
/**
* Return CmlCatalog with only products - because in package no data about
* inventory type.
* @param SimpleXMLElement $package
* @param CmlCatalog $cmlCatalog
* @return \CmlCatalog
*/
protected function initilizatePackageInventories($packageOffers, $cmlCatalog) {
foreach($packageOffers->Предложение as $offer) {
$inventory = $this->initilizatePackageInventory($offer);
if($inventory->getCurrency() == NULL) {
$inventory->setCurrency($cmlCatalog->getCurrency());
}
$cmlCatalog->addProduct($inventory);
}
return $cmlCatalog;
}
/**
* Initilizate inventory cost parameters by getted SimpleXMLElement.
* @param SimpleXMLElement $offer
* @return \CmlProduct
*/
protected function initilizatePackageInventory($offer) {
$priceXmlElement = $this->getMandatoryPriceElement($offer);
$price = $this->getMandatoryChildContent($priceXmlElement, 'ЦенаЗаЕдиницу',
'Not product price in offers.xml');
$currency = $this->getChildContent($priceXmlElement, 'Валюта');
$conversionRate = $this->getChildContent($priceXmlElement, 'Коэффициент');
$name = $this->getMandatoryChildContent($offer, 'Наименование',
'Not product name in offers.xml');
$name = $this->filter($name);
$oneEsIdentifier = $this->getMandatoryChildContent($offer, 'Ид',
'Not product identificator in offers.xml');
$count = $this->getChildContent($offer, 'Количество');
$inventory = new CmlProduct();
$inventory->offersInitilizate($oneEsIdentifier, $name, $price, $currency, $conversionRate, $count);
return $inventory;
}
/**
* Initilizate account from document. If no account - throw exception.
* @param CmlSalesOrder $salesOrder
* @param SimpleXMLElement $order
* @return CmlSalesOrder
*/
protected function getDocumentAccount($salesOrder, $xmlOrder) {
$xmlAccount = $xmlOrder;
if($this->isChildExists($xmlOrder, 'Контрагенты')) {
$xmlAccount = $xmlOrder->Контрагенты;
}
$this->checkMandatoryChildElement($xmlAccount, 'Контрагент', 'Not account in order! Order number - ' . $salesOrder->getNumber());
$account = $xmlAccount->Контрагент;
$oneEsIdentifier = $this->getMandatoryChildContent($account, 'Ид', 'Not account id in order! Order number - ' . $salesOrder->getNumber());
/* Phisical or legal face */
$accountName = $this->getChildContent($account, 'ПолноеНаименование');
if($accountName == null) {
$accountName = $this->getMandatoryChildContent($account, 'ОфициальноеНаименование', 'Not account name in order! Order number - ' . $salesOrder->getNumber());
}
$accountName = $this->filter($accountName);
$inn = $this->getChildContent($account, 'ИНН');
$kpp = $this->getChildContent($account, 'КПП');
$cmlAccount = new CmlAccount($accountName, $oneEsIdentifier);
$cmlAccount->initAccountTaxInfo($inn, $kpp);
$this->parseAccountAddress($cmlAccount, $account);
$salesOrder->addAccount($cmlAccount);
return $salesOrder;
}
/**
* Initlizate account address if it exists.
* @param CmlAccount $cmlAccount
* @param SimpleXmlElement $xmlAccount
*/
protected function parseAccountAddress($cmlAccount, $xmlAccount) {
//TODO: In next version diff phis and legal addreses
$address = null;
/* Phisical or legal face */
if($this->isChildExists($xmlAccount, 'АдресРегистрации')) {
$xmlAddress = $xmlAccount->АдресРегистрации;
} elseif($this->isChildExists($xmlAccount, 'Адрес')) {
$xmlAddress = $xmlAccount->Адрес;
} else {
return;
}
/* Parse addres fields */
foreach($xmlAddress->АдресноеПоле as $xmlAddressPart) {
if($this->isChildExists($xmlAddressPart, 'Значение')) {
$address = $address.$this->getChildContent($xmlAddressPart, 'Значение')." ";
}
}
if($address != null) {
$cmlAccount->initAccountAddress($address, $address); //shipping and billing equals in this version
}
}
/**
* Parse all order products and services. If no one servicew or product - throw exception.
* @param CmlSalesOrder $salesOrder
* @param SimpleXMLElement $order
* @return CmlSalesOrder
*/
protected function initilizateOrderInventories($salesOrder, $order) {
$this->checkMandatoryChildElement($order, 'Товары', 'Not products in order!' . $salesOrder->getNumber());
$orderInventories = $order->Товары;
$this->checkMandatoryChildElement($orderInventories, 'Товар', 'No one product or service in order. Order number - ' . $salesOrder->getNumber());
foreach($orderInventories->Товар as $xmlInventory) {
if($this->isProduct($xmlInventory)) {
$inventory = new CmlProduct();
$inventory = $this->initilizateOrderInventory($xmlInventory, $inventory, $salesOrder);
$salesOrder->addProduct($inventory);
} else {
$inventory = new CmlService();
$inventory = $this->initilizateOrderInventory($xmlInventory, $inventory, $salesOrder);
$salesOrder->addService($inventory);
}
}
return $salesOrder;
}
/**
* Initilizate AbstractProduct by order xml.
* @param SimpleXmlElement $orderProduct
* @param AbstractProduct $inventory
* @param CmlSalesOrder $salesOrder
* @return AbstractProduct
*/
protected function initilizateOrderInventory($orderProduct, $inventory, $salesOrder) {
$name = $this->getMandatoryChildContent($orderProduct, 'Наименование', 'Not product name in order! Order number - ' . $salesOrder->getNumber());
$oneEsIdentifier = $this->getMandatoryChildContent($orderProduct, 'Ид', 'Not product identificator in order. Order number - ' . $salesOrder->getNumber());
$price = $this->getMandatoryChildContent($orderProduct, 'ЦенаЗаЕдиницу', 'Not product price in order. Order number - ' . $salesOrder->getNumber());
$count = $this->getMandatoryChildContent($orderProduct, 'Количество', 'Not product count in order. Order number - ' . $salesOrder->getNumber());
$unitName = '';
if($this->isChildExists($orderProduct, 'БазоваяЕдиница')) {
$unitName = $this->getBasicUnitFromXml($orderProduct->БазоваяЕдиница);
}
$article = $this->getChildContent($orderProduct, 'Артикул');
$NDS = $this->getTaxRate($orderProduct);
$name = $this->filter($name);
$article = $this->filter($article);
$inventory->orderInitilizate($oneEsIdentifier, $name, $article, $unitName, $price, $count, $NDS);
return $inventory;
}
/**
* Return basic unit value from xml description
* @param SimpleXMLElement $unitXml
*/
protected function getBasicUnitFromXml($unitXml) {
$unitCode = (string) $unitXml['Код'];
$unitValue = UnitsConverter::convertFrom1cToCrm($unitCode);
if($unitValue == null) {
$unitValue = (string) $unitXml['НаименованиеПолное'];
}
return $unitValue;
}
/**
* Initilizate order props
* @param CmlSalesOrder $salesOrder
* @param SimpleXmlElement $xmlOrder
* @return CmlSalesOrder
*/
protected function initilizateOrderProps($salesOrder, $xmlOrder) {
if($this->isChildExists($xmlOrder, 'ЗначенияРеквизитов')) {
$xmlProps = $xmlOrder->ЗначенияРеквизитов;
foreach($xmlProps->ЗначениеРеквизита as $prop) {
$propName = $this->getChildContent($prop, 'Наименование');
$propValue = $this->getChildContent($prop, 'Значение');
$salesOrder->addProp($propName, $propValue);
}
}
return $salesOrder;
}
/**
* Return SimpleXmlElement describes price of product.
* @param SimpleXmlElement $offer
* @return SimpleXmlElement
*/
protected function getMandatoryPriceElement($offer) {
$this->checkMandatoryChildElement($offer, "Цены", "Not product price in offers!");
$prices = $offer->Цены;
$this->checkMandatoryChildElement($prices,"Цена","Not product price in offers!");
return $prices->Цена;
}
}