614 lines
18 KiB
PHP
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());
|
|
}
|
|
}
|