Files
kupshop/bundles/External/FlexiBeeBundle/Util/FlexiBeeApi.php
2025-08-02 16:30:27 +02:00

614 lines
18 KiB
PHP

<?php
declare(strict_types=1);
namespace External\FlexiBeeBundle\Util;
use AbraFlexi\Adresar;
use AbraFlexi\Cenik;
use AbraFlexi\Changes;
use AbraFlexi\Company;
use AbraFlexi\FakturaVydana;
use AbraFlexi\ObjednavkaPrijata;
use AbraFlexi\ObjednavkaPrijataPolozka;
use AbraFlexi\SkladovaKarta;
use AbraFlexi\StromCenik;
use AbraFlexi\UcetniObdobi;
use External\FlexiBeeBundle\AbraFlexiTypes\CenikovaSkupina;
use External\FlexiBeeBundle\AbraFlexiTypes\FakturaVydanaPolozka;
use External\FlexiBeeBundle\AbraFlexiTypes\FormaDopravy;
use External\FlexiBeeBundle\AbraFlexiTypes\Odberatel;
use External\FlexiBeeBundle\AbraFlexiTypes\Sklad;
use External\FlexiBeeBundle\AbraFlexiTypes\Stredisko;
use External\FlexiBeeBundle\Exception\FlexiBeeException;
class FlexiBeeApi
{
/**
* Data, které u jednotlivých typů načítáme.
*
* https://demo.flexibee.eu/c/demo/{evidence}/properties
*/
protected array $defaultColumnsByEvidence = [
'adresar' => [
'id', 'kod', 'typVztahuK', 'email', 'canceled', 'nazev', 'ulice', 'mesto', 'psc', 'tel', 'mobil', 'ic',
'dic', 'stat', 'postovniShodna', 'faJmenoFirmy', 'faUlice', 'faMesto', 'faPsc', 'faStat', 'stitky', 'splatDny', 'skupCen',
],
'skladova-karta' => [
'lastUpdate', 'sklad', 'cenik', 'stavMJ', 'dostupMj',
],
'strom-cenik' => [
'id', 'idZaznamu', 'uzel',
],
'cenik' => [
'id', 'lastUpdate', 'typZasobyK', 'kod', 'eanKod', 'nazev', 'cenaZaklBezDph', 'typSzbDphK', 'sumDostupMj', 'hmotMj', 'hmotObal', 'exportNaEshop',
],
'objednavka-prijata' => [
'id', 'lastUpdate', 'kod', 'cisDosle', 'mena', 'stavUzivK', 'storno', 'formaDopravy', 'formaUhradyCis',
'kontaktEmail', 'kontaktJmeno', 'kontaktTel', 'nazFirmy', 'ulice', 'mesto', 'psc', 'ic', 'dic', 'stat',
'postovniShodna', 'faNazev', 'faUlice', 'faMesto', 'faPsc', 'faStat', 'doprava',
],
'objednavka-prijata-polozka' => [
'id', 'lastUpdate', 'doklObch', 'kod', 'nazev', 'cisRad', 'typPolozkyK', 'mnozMj', 'typCenyDphK', 'szbDph', 'cenaMj', 'cenik', 'storno', 'stornoPol', 'slevaPol',
],
'odberatel' => [
'id', 'lastUpdate', 'kodIndi', 'prodejCena', 'cenik', 'skupCen', 'mena',
],
];
private FlexiBeeConfiguration $configuration;
private FlexiBeeUtil $flexiBeeUtil;
public function __construct(FlexiBeeConfiguration $configuration, FlexiBeeUtil $flexiBeeUtil)
{
$this->configuration = $configuration;
$this->flexiBeeUtil = $flexiBeeUtil;
}
/**
* Zkontroluje připojení k FlexiBee - ověří správnost údajů vyplněných v administraci.
*/
public function isConnectionValid(): bool
{
try {
$company = $this->getApiWorker(Company::class);
$data = $company->getFlexiData();
} catch (FlexiBeeException $e) {
return false;
}
return !empty($data);
}
public function isChangesAPIEnabled(): bool
{
$changes = $this->getApiWorker(Changes::class);
return (bool) $changes->getStatus();
}
public function changesAPIEnable(): bool
{
$changes = $this->getApiWorker(Changes::class);
return (bool) $changes->enable();
}
/**
* Vrací seznam změněných objektů ve FlexiBee.
*/
public function getChanges(int $start, ?string $evidenceClass = null, int $limit = 500): array
{
$changes = $this->getApiWorker(Changes::class);
// Musim to takhle hacknout, protoze jinak to zacne hazet chybu, ze to nezna "evidence" column
// To changes API je asi pomerne novy a ta knihovna to nema uplne posefeny
$changes->urlParams = array_merge($changes->urlParams, [
'evidence' => ['type' => 'string', 'description' => 'Evidence selection'],
]);
$evidence = null;
// Pokud chci zmeny pro pouze urcitou evidenci
if ($evidenceClass) {
$evidence = $this->getApiWorker($evidenceClass)->getEvidence();
}
$filter = array_filter([
'start' => $start,
'evidence' => $evidence,
'limit' => $limit,
]);
return $changes->getAllFromAbraFlexi(!empty($filter) ? $filter : null);
}
public function createOrUpdateUser(array $user): int
{
$adresar = $this->getApiWorker(Adresar::class);
$adresar->insertToAbraFlexi($user);
return (int) $adresar->getLastInsertedId();
}
public function getUserIdByEmail(string $email): ?int
{
$adresar = $this->getApiWorker(Adresar::class);
$results = $adresar->getAllFromAbraFlexi(
$this->getFilters(['id'], ['email' => $email])
);
$result = reset($results);
return $result ? (int) $result['id'] : null;
}
public function getUserIdByCode(string $code): ?int
{
$adresar = $this->getApiWorker(Adresar::class);
$results = $adresar->getAllFromAbraFlexi(
$this->getFilters(['id'], ['kod' => $code])
);
$result = reset($results);
return $result ? (int) $result['id'] : null;
}
public function getUsers(?\DateTime $lastUpdate = null): iterable
{
$adresar = $this->getApiWorker(Adresar::class);
return $this->withPagination(
$adresar,
$this->getFilters(
$this->getColumnsByWorker($adresar),
[],
$lastUpdate
)
);
}
/**
* Vrátí položky podle zadaných ID z dané evidence.
*/
public function getEvidenceDataByIds(string $evidenceClass, array $ids, ?array $columns = null, array $filters = []): array
{
$worker = $this->getApiWorker($evidenceClass);
if ($columns === null) {
$columns = $this->getColumnsByWorker($worker);
}
return $worker->getAllFromAbraFlexi(
$this->getFilters($columns, array_merge(['limit' => 0, 'id IN ('.implode(',', $ids).')'], $filters))
);
}
public function getOrderInvoice(string $id): ?array
{
return $this->fetchInvoiceByField('id', 'ext:FAV:'.$id);
}
/**
* Vrátí pdf fakturu.
*/
public function getOrderInvoicePdf(\Order $order): ?string
{
$invoice = $this->fetchInvoiceByField('cisObj', $order->order_no);
if (!$invoice) {
return null;
}
$invoiceWorker = $this->getApiWorker(FakturaVydana::class);
$invoiceWorker->processInit($invoice);
return $invoiceWorker->getInFormat('pdf', 'fakturaKB$$SUM', $order->getLanguage());
}
private function fetchInvoiceByField(string $field, string $value): ?array
{
$apiWorker = $this->getApiWorker(FakturaVydana::class);
$results = $apiWorker->getAllFromAbraFlexi(
$this->getFilters([], [$field => $value])
);
$result = reset($results);
return $result ?: null;
}
public function updateOrderInvoice(array $data): int
{
$fakturaVydana = $this->getApiWorker(FakturaVydana::class);
$fakturaVydana->insertToAbraFlexi($data);
if (!($flexiInvoiceId = $fakturaVydana->getLastInsertedId())) {
throw new FlexiBeeException('Invoice was not updated');
}
return (int) $flexiInvoiceId;
}
public function realizeOrder(string $invoiceNumber, array $dataRealize, array $dataInvoice): int
{
$objednavkaPrijata = $this->getApiWorker(ObjednavkaPrijata::class);
$objednavkaPrijata->insertToAbraFlexi($dataRealize);
if (!($flexiOrderId = $objednavkaPrijata->getLastInsertedId())) {
throw new FlexiBeeException('Order failure! Order was not successfully realized in Flexi');
}
// give Flexi some time
sleep(1);
if ($invoice = $this->getOrderInvoice($invoiceNumber)) {
if (!empty($invoice['id'])) {
$dataInvoice['id'] = $invoice['id'];
$this->updateOrderInvoice($dataInvoice);
}
}
return (int) $flexiOrderId;
}
public function createOrUpdateOrder(array $data): int
{
$objednavkaPrijata = $this->getApiWorker(ObjednavkaPrijata::class);
$objednavkaPrijata->insertToAbraFlexi($data);
if (!($flexiOrderId = $objednavkaPrijata->getLastInsertedId())) {
throw new FlexiBeeException('Something went wrong during sending order to FlexiBee! Last inserted ID was not returned.');
}
return (int) $flexiOrderId;
}
public function getOrder(int $flexiOrderId): ?array
{
$objednavkaPrijata = $this->getApiWorker(ObjednavkaPrijata::class);
$data = $objednavkaPrijata->getAllFromAbraFlexi(
$this->getFilters($this->getColumnsByWorker($objednavkaPrijata), ['limit' => 0, 'id' => $flexiOrderId])
);
$data = reset($data);
if (empty($data)) {
return null;
}
return $data;
}
public function getOrdersItems(array $ids): array
{
$objednavkaPrijataPolozka = $this->getApiWorker(ObjednavkaPrijataPolozka::class);
$items = $objednavkaPrijataPolozka->getAllFromAbraFlexi(
$this->getFilters($this->getColumnsByWorker($objednavkaPrijataPolozka), ['limit' => 0, 'doklObch IN ('.implode(',', $ids).')'])
);
$itemsByOrders = [];
foreach ($items as $item) {
$itemsByOrders[$this->flexiBeeUtil->getFlexiIdFromRef($item['doklObch']->ref)][] = $item;
}
return $itemsByOrders;
}
public function getOrderItems(int $flexiOrderId): array
{
$objednavkaPrijataPolozka = $this->getApiWorker(ObjednavkaPrijataPolozka::class);
return $objednavkaPrijataPolozka->getAllFromAbraFlexi(
$this->getFilters($this->getColumnsByWorker($objednavkaPrijataPolozka), ['limit' => 0, 'doklObch' => $flexiOrderId])
);
}
public function getInvoiceItems(int $flexiOrderId): array
{
$fakturaVydanaPolozka = $this->getapiWorker(FakturaVydanaPolozka::class);
return $fakturaVydanaPolozka->getAllFromAbraFlexi(
$this->getFilters($this->getColumnsByWorker($fakturaVydanaPolozka), ['limit' => 0, 'doklFak' => $flexiOrderId])
);
}
/**
* Vrátí všechna střediska ve FlexiBee.
*/
public function getCentrals(): array
{
return $this->getApiWorker(Stredisko::class)
->getAllFromAbraFlexi();
}
public function getDeliveries(): array
{
return $this->getApiWorker(FormaDopravy::class)
->getAllFromAbraFlexi();
}
/**
* Vrátí seznam skladů ve FlexiBee.
*
* @param bool $all - pokud je false, tak se sklady filtrují podle nastavení v administraci
*/
public function getStores(bool $all = false): array
{
$store = $this->getApiWorker(Sklad::class);
$filter = null;
if (!$all) {
$filter = ['id IN ('.implode(',', $this->configuration->getEnabledStoreIds()).')'];
}
return $store->getAllFromAbraFlexi($filter);
}
/**
* Vrátí seznam ceníků ve FlexiBee.
*/
public function getPriceLists(): array
{
$priceList = $this->getApiWorker(CenikovaSkupina::class);
return $priceList->getAllFromAbraFlexi();
}
/**
* Vrátí skladové karty z FlexiBee.
*/
public function getStockCards(?\DateTime $lastUpdate = null, ?array $flexiProductIds = null): iterable
{
$skladovaKarta = $this->getApiWorker(SkladovaKarta::class);
$filter = [
'limit' => 1000,
'sklad in ('.implode(',', $this->configuration->getEnabledStoreIds()).')',
'no-ext-ids' => true,
'ucetObdobi' => 'code:'.$this->getCurrentAccountingPeriod(),
];
if ($flexiProductIds !== null) {
$filter[] = 'cenik in ('.implode(',', $flexiProductIds).')';
}
return $this->withPagination(
$skladovaKarta,
$this->getFilters(
$this->getColumnsByWorker($skladovaKarta),
$filter,
$lastUpdate
)
);
}
/**
* Vrátí aktuální účetní období fe FlexiBee.
*/
public function getCurrentAccountingPeriod(bool $force = false): string
{
$cacheKey = 'flexiBee_currentAccountingPeriod';
if (!$force && ($currentAccountingPeriod = getCache($cacheKey))) {
return $currentAccountingPeriod;
}
$ucetniObdobi = $this->getApiWorker(UcetniObdobi::class);
$date = (new \DateTime())->format('Y-m-d');
$filters = [
'platiOdData <= "'.$date.'" and platiDoData >= "'.$date.'"',
];
$accountingPeriod = $ucetniObdobi->getAllFromAbraFlexi(
$this->getFilters(['id', 'kod'], $filters)
);
$accountingPeriod = reset($accountingPeriod);
if (!$accountingPeriod) {
throw new FlexiBeeException('Current accounting period not found!');
}
setCache($cacheKey, $accountingPeriod['kod'], 3600);
return $accountingPeriod['kod'];
}
public function getProductsSections(): array
{
$stromCenik = $this->getApiWorker(StromCenik::class);
$filter = [
'limit' => 0,
];
return $stromCenik->getAllFromAbraFlexi(
$this->getFilters(
$this->getColumnsByWorker($stromCenik),
$filter
)
);
}
/**
* Vrátí produkty z FlexiBee.
*/
public function getProducts(?\DateTime $lastUpdate = null): iterable
{
$cenik = $this->getApiWorker(Cenik::class);
$filter = [
'limit' => 500,
'typZasobyK in ("typZasoby.zbozi", "typZasoby.vyrobek")',
];
return $this->withPagination(
$cenik,
$this->getFilters(
$this->getColumnsByWorker($cenik),
$filter,
$lastUpdate
)
);
}
public function getPricelistPrices(?\DateTime $lastUpdate = null, ?array $flexiProductIds = null): iterable
{
$worker = $this->getApiWorker(Odberatel::class);
$filter = [
'limit' => 500,
'skupCen is not null',
];
if ($flexiProductIds !== null) {
$filter[] = 'cenik in ('.implode(',', $flexiProductIds).')';
}
return $this->withPagination(
$worker,
$this->getFilters(
$this->getColumnsByWorker($worker),
$filter,
$lastUpdate,
)
);
}
public function getProductByCode(string $code): ?array
{
$cenik = $this->getApiWorker(Cenik::class);
$filter = [
'limit' => 0,
'kod' => $code,
];
$products = $cenik->getAllFromAbraFlexi(
$this->getFilters($this->getColumnsByWorker($cenik), $filter)
);
$product = reset($products);
if ($product) {
return $product;
}
return null;
}
public function getProductPrices(int $flexiProductId): ?array
{
$cenik = $this->getApiWorker(Cenik::class);
$data = $cenik->getAllFromAbraFlexi(
$this->getFilters($this->getColumnsByWorker($cenik), ['limit' => 0, 'id' => $flexiProductId])
);
$data = reset($data);
if (empty($data)) {
return null;
}
return $data;
}
/**
* Vrátí ceny produktů ve FlexiBee.
*/
public function getPrices(?\DateTime $lastUpdate = null): iterable
{
$cenik = $this->getApiWorker(Cenik::class);
$columns = [
'id',
'lastUpdate',
'kod',
'cenaZaklBezDph',
'typSzbDphK',
];
$filter = [
'limit' => 500,
'typZasobyK in ("typZasoby.zbozi", "typZasoby.vyrobek")',
];
return $this->withPagination(
$cenik,
$this->getFilters($columns, $filter, $lastUpdate)
);
}
/**
* Pomocná funkce pro stránkování.
*/
private function withPagination(FlexiBeeApiWorker $worker, array $filters = []): iterable
{
$totalRows = $this->getDataRowCount($worker, $filters);
$limit = $filters['limit'] ?? 100;
$iterationLimit = $totalRows / $limit;
for ($i = 0; $i < $iterationLimit; $i++) {
// posunout offset
$filters['start'] = $i * $limit;
// nacist data
foreach ($worker->getAllFromAbraFlexi($filters) as $item) {
yield $item;
}
}
}
/**
* Pomocná funkce, která vrací celkový počet položek pro daný filtr.
*/
private function getDataRowCount(FlexiBeeApiWorker $worker, array $filters): int
{
$filters['limit'] = 1;
$filters['add-row-count'] = 'true';
$worker->getAllFromAbraFlexi($filters);
return (int) $worker->rowCount;
}
protected function getColumnsByWorker(FlexiBeeApiWorker $worker): array
{
$evidence = $worker->getEvidence();
$columns = $this->defaultColumnsByEvidence[$evidence] ?? [];
if (findModule(\Modules::OSS_VATS) && $evidence == 'cenik') {
$columns[] = 'nomen';
}
return $columns;
}
private function getFilters(array $columns = [], array $filters = [], ?\DateTime $lastUpdate = null): array
{
if (!empty($columns)) {
$filters['detail'] = 'custom:'.implode(',', $columns);
}
if ($lastUpdate) {
$filters['lastUpdate'] = '> '.$lastUpdate->format('Y-m-d H:i:s');
}
return $filters;
}
private function getApiWorker(string $worker): FlexiBeeApiWorker
{
return FlexiBeeApiWorker::create($worker, $this->configuration->getAPIConfig());
}
}