YetiForceCompany/YetiForceCRM

View on GitHub
app/Integrations/Magento/Synchronizer/Base.php

Summary

Maintainability
C
1 day
Test Coverage
F
0%
<?php
/**
 * Synchronize.
 *
 * The file is part of the paid functionality. Using the file is allowed only after purchasing a subscription. File modification allowed only with the consent of the system producer.
 *
 * @package Integration
 *
 * @copyright YetiForce S.A.
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
 * @author    Tomasz Kur <t.kur@yetiforce.com>
 * @author    Arkadiusz Dudek <a.dudek@yetiforce.com>
 * @author    Mariusz Krzaczkowski <m.krzaczkowski@yetiforce.com>
 */

namespace App\Integrations\Magento\Synchronizer;

/**
 * Base class to synchronization.
 */
abstract class Base
{
    /**
     * Connector.
     *
     * @var \App\Integrations\Magento\Connector\Token
     */
    protected $connector;
    /**
     * Last scan config data.
     *
     * @var array
     */
    public $lastScan = [];
    /**
     * Config.
     *
     * @var \App\Integrations\Magento\Config
     */
    public $config;
    /**
     * Controller.
     *
     * @var \App\Integrations\Magento\Controller
     */
    public $controller;

    /**
     * Constructor.
     *
     * @param \App\Integrations\Magento\Controller $controller
     */
    public function __construct(\App\Integrations\Magento\Controller $controller)
    {
        $this->connector = $controller->getConnector();
        $this->controller = $controller;
        $this->config = $controller->config;
    }

    /**
     * Main function.
     *
     * @return void
     */
    abstract public function process();

    /**
     * Return parsed time to magento time zone.
     *
     * @param string $value
     *
     * @return string
     */
    public function getFormattedTime(string $value): string
    {
        return \DateTimeField::convertTimeZone($value, \App\Fields\DateTime::getTimeZone(), 'UTC')->format('Y-m-d H:i:s');
    }

    /**
     * Save inventory elements.
     *
     * @param \Vtiger_Record_Model                                  $recordModel
     * @param \App\Integrations\Magento\Synchronizer\Maps\Inventory $mapModel
     *
     * @return bool
     */
    public function saveInventoryCrm(\Vtiger_Record_Model $recordModel, Maps\Inventory $mapModel): bool
    {
        $inventoryData = [];
        $savedAllProducts = true;
        if ($mapModel->dataCrm['currency_id']) {
            foreach ($mapModel->data['items'] as $item) {
                $productId = $this->findProduct(trim($item['sku']));
                if (0 === $productId) {
                    $productId = $mapModel->createProduct($item);
                }
                if ($productId) {
                    $item['crmProductId'] = $productId;
                    $inventoryData[] = $this->parseInventoryData($recordModel, $item, $mapModel);
                } else {
                    $savedAllProducts = false;
                    \App\Log::error('Skipped saving record, product not found in CRM (magento id: [' . $item['product_id'] . '] | SKU:[' . $item['sku'] . '])', 'Integrations/Magento');
                    $this->log('Skipped saving record, product not found in CRM (magento id: [' . $item['product_id'] . '] | SKU:[' . $item['sku'] . '])');
                    break;
                }
            }
        } else {
            $savedAllProducts = false;
        }
        if ($savedAllProducts && !empty($inventoryData)) {
            if (!empty($mapModel->data['extension_attributes']['shipping_assignments']) && ($shipping = $this->parseShippingData($mapModel))) {
                $inventoryData[] = $shipping;
            }
            if ($additionalData = $this->findAdditionalData($mapModel)) {
                $inventoryData[] = $additionalData;
            }
            $recordModel->initInventoryData($inventoryData, false);
        }
        return $savedAllProducts;
    }

    /**
     * Parse inventory data to YetiForce format.
     *
     * @param \Vtiger_Record_Model                                  $recordModel
     * @param array                                                 $item
     * @param \App\Integrations\Magento\Synchronizer\Maps\Inventory $mapModel
     *
     * @return array
     */
    public function parseInventoryData(\Vtiger_Record_Model $recordModel, array $item, Maps\Inventory $mapModel): array
    {
        $mapModel->setDataInv($item);
        $inventoryModel = \Vtiger_Inventory_Model::getInstance($recordModel->getModuleName());
        $inventoryRow = $inventoryModel->loadRowData($item['crmProductId'], ['currency' => $mapModel->dataCrm['currency_id']]);
        foreach ($inventoryModel->getFields() as $columnName => $fieldModel) {
            if (\in_array($fieldModel->getColumnName(), ['name', 'total', 'margin', 'marginp', 'net', 'gross'])) {
                continue;
            }
            if ('tax_percent' === $columnName || 'tax' === $columnName) {
                $tax = $item['tax_percent'] ?? round($item['tax_amount'] / $item['row_total'] * 100);
                $inventoryRow['taxparam'] = '{"aggregationType":"individual","individualTax":' . $tax . '}';
            } elseif ('taxmode' === $columnName) {
                $inventoryRow['taxmode'] = 1;
            } elseif ('discountmode' === $columnName) {
                $inventoryRow['discountmode'] = 1;
            } elseif ('discount' === $columnName) {
                if (empty($item['discount_amount']) && !empty($item['discount_percent'])) {
                    $inventoryRow['discountparam'] = '{"aggregationType":"individual","individualDiscountType":"percentage","individualDiscount":' . $item['discount_percent'] . '}';
                } else {
                    $inventoryRow['discountparam'] = '{"aggregationType":"individual","individualDiscountType":"amount","individualDiscount":' . $mapModel->getInvFieldValue('discount') . '}';
                }
            } elseif ('currency' === $columnName) {
                $inventoryRow['currency'] = $mapModel->dataCrm['currency_id'];
            } else {
                $value = $mapModel->getInvFieldValue($columnName);
                if (null !== $value) {
                    $inventoryRow[$columnName] = $value;
                } elseif (!isset($inventoryRow[$columnName])) {
                    $inventoryRow[$columnName] = $fieldModel->getDefaultValue();
                }
            }
        }
        return $inventoryRow;
    }

    /**
     * Parse shipping data.
     *
     * @param \App\Integrations\Magento\Synchronizer\Maps\Inventory $mapModel
     *
     * @return array
     */
    public function parseShippingData(Maps\Inventory $mapModel): array
    {
        $data = current($mapModel->data['extension_attributes']['shipping_assignments']);
        if ($this->config->get('shipping_service_id') && !empty($data['shipping']['total'])) {
            $tax = $data['shipping']['total']['shipping_amount'] > 0 ? ($data['shipping']['total']['shipping_tax_amount'] / $data['shipping']['total']['shipping_amount'] * 100) : 0;
            return [
                'discountmode' => 1,
                'taxmode' => 1,
                'currency' => $mapModel->dataCrm['currency_id'],
                'name' => $this->config->get('shipping_service_id'),
                'unit' => '',
                'subunit' => '',
                'qty' => 1,
                'price' => $data['shipping']['total']['shipping_amount'],
                'discountparam' => '{"aggregationType":"individual","individualDiscountType":"amount","individualDiscount":' . $data['shipping']['total']['shipping_discount_amount'] . '}',
                'purchase' => 0,
                'taxparam' => '{"aggregationType":"individual","individualTax":' . round($tax) . '}',
                'comment1' => '',
            ];
        }
        return [];
    }

    /**
     * Parse additional data.
     *
     * @param \App\Integrations\Magento\Synchronizer\Maps\Inventory $mapModel
     *
     * @return array
     */
    public function findAdditionalData(Maps\Inventory $mapModel): array
    {
        $additionalData = [];
        if (method_exists($mapModel, 'addAdditionalInvData')) {
            $additionalData = $mapModel->addAdditionalInvData();
        }
        return $additionalData;
    }

    /**
     * Find product id by ean.
     *
     * @param string $ean
     *
     * @return int
     */
    public function findProduct(string $ean): int
    {
        if (\App\Cache::staticHas('ProductIdByEan', $ean)) {
            return \App\Cache::staticGet('ProductIdByEan', $ean);
        }
        $id = (new \App\Db\Query())->select(['productid'])->from('vtiger_products')
            ->innerJoin('vtiger_crmentity', 'vtiger_products.productid = vtiger_crmentity.crmid')
            ->where(['vtiger_crmentity.deleted' => 0, 'vtiger_products.ean' => $ean])->scalar() ?: 0;
        \App\Cache::staticSave('ProductIdByEan', $ean, $id);
        return $id;
    }

    /**
     * Add log to db.
     *
     * @param string      $category
     * @param ?\Throwable $ex
     *
     * @return void
     */
    public function log(string $category, ?\Throwable $ex = null): void
    {
        \App\DB::getInstance('log')->createCommand()
            ->insert('l_#__magento', [
                'time' => date('Y-m-d H:i:s'),
                'category' => $ex ? $category : 'info',
                'message' => $ex ? $ex->getMessage() : $category,
                'code' => $ex ? $ex->getCode() : 500,
                'trace' => $ex ? $ex->__toString() : null,
            ])->execute();
    }
}