<?php

namespace SystemConnector\TransferObject\Order;

use DateTimeImmutable;
use ReflectionClass;
use SystemConnector\TransferObject\AbstractTransferObject;
use SystemConnector\TransferObject\AttributableInterface;
use SystemConnector\TransferObject\Order\Address\Address;
use SystemConnector\TransferObject\Order\Comment\Comment;
use SystemConnector\TransferObject\Order\Customer\Customer;
use SystemConnector\TransferObject\Order\OrderItem\OrderItem;
use SystemConnector\TransferObject\Order\Package\Package;
use SystemConnector\ValueObject\Attribute\Attribute;

class Order extends AbstractTransferObject implements AttributableInterface
{
    const TYPE = 'Order';

    /**
     * Identifier of the object.
     *
     * @var string
     */
    private $identifier = '';

    /**
     * @var string
     */
    private $orderNumber = '';

    /**
     * @var DateTimeImmutable;
     */
    private $orderTime;

    /**
     * @var null|Customer
     */
    private $customer;

    /**
     * @var null|Address
     */
    private $billingAddress;

    /**
     * @var null|Address
     */
    private $shippingAddress;

    /**
     * @var OrderItem[]
     */
    private $orderItems = [];

    /**
     * @var string
     */
    private $shopIdentifier = '';

    /**
     * @var string
     */
    private $currencyIdentifier = '';

    /**
     * @var string
     */
    private $orderStatusIdentifier = '';

    /**
     * @var string
     */
    private $paymentStatusIdentifier = '';

    /**
     * @var string
     */
    private $paymentMethodIdentifier = '';

    /**
     * @var string
     */
    private $shippingProfileIdentifier = '';

    /**
     * @var Comment[]
     */
    private $comments = [];

    /**
     * @var Package[]
     */
    private $packages = [];

    /**
     * @var Attribute[]
     */
    private $attributes = [];

    public function __construct()
    {
        $this->orderTime = new DateTimeImmutable('now');
    }

    /**
     * {@inheritdoc}
     */
    public function getType()
    {
        return self::TYPE;
    }

    /**
     * {@inheritdoc}
     */
    public function getIdentifier()
    {
        return $this->identifier;
    }

    /**
     * {@inheritdoc}
     */
    public function setIdentifier($identifier)
    {
        $this->identifier = $identifier;
    }

    /**
     * @return array
     */
    public function getOrderTypes()
    {
        $reflection = new ReflectionClass(__CLASS__);

        return $reflection->getConstants();
    }

    /**
     * @return string
     */
    public function getOrderNumber()
    {
        return $this->orderNumber;
    }

    /**
     * @param string $orderNumber
     */
    public function setOrderNumber($orderNumber)
    {
        $this->orderNumber = $orderNumber;
    }

    /**
     * @return DateTimeImmutable
     */
    public function getOrderTime()
    {
        return $this->orderTime;
    }

    /**
     * @param DateTimeImmutable $orderTime
     */
    public function setOrderTime(DateTimeImmutable $orderTime)
    {
        $this->orderTime = $orderTime;
    }

    /**
     * @return Customer
     */
    public function getCustomer()
    {
        return $this->customer;
    }

    /**
     * @param Customer $customer
     */
    public function setCustomer($customer)
    {
        $this->customer = $customer;
    }

    /**
     * @return Address
     */
    public function getBillingAddress()
    {
        return $this->billingAddress;
    }

    /**
     * @param Address $billingAddress
     */
    public function setBillingAddress(Address $billingAddress)
    {
        $this->billingAddress = $billingAddress;
    }

    /**
     * @return Address
     */
    public function getShippingAddress()
    {
        return $this->shippingAddress;
    }

    /**
     * @param Address $shippingAddress
     */
    public function setShippingAddress(Address $shippingAddress)
    {
        $this->shippingAddress = $shippingAddress;
    }

    /**
     * @return OrderItem[]
     */
    public function getOrderItems()
    {
        return $this->orderItems;
    }

    /**
     * @param OrderItem[] $orderItems
     */
    public function setOrderItems(array $orderItems)
    {
        $this->orderItems = $orderItems;
    }

    /**
     * @return string
     */
    public function getShopIdentifier()
    {
        return $this->shopIdentifier;
    }

    /**
     * @param string $shopIdentifier
     */
    public function setShopIdentifier($shopIdentifier)
    {
        $this->shopIdentifier = $shopIdentifier;
    }

    /**
     * @return string
     */
    public function getCurrencyIdentifier()
    {
        return $this->currencyIdentifier;
    }

    /**
     * @param string $currencyIdentifier
     */
    public function setCurrencyIdentifier($currencyIdentifier)
    {
        $this->currencyIdentifier = $currencyIdentifier;
    }

    /**
     * @return string
     */
    public function getOrderStatusIdentifier()
    {
        return $this->orderStatusIdentifier;
    }

    /**
     * @param string $orderStatusIdentifier
     */
    public function setOrderStatusIdentifier($orderStatusIdentifier)
    {
        $this->orderStatusIdentifier = $orderStatusIdentifier;
    }

    /**
     * @return string
     */
    public function getPaymentStatusIdentifier()
    {
        return $this->paymentStatusIdentifier;
    }

    /**
     * @param string $paymentStatusIdentifier
     */
    public function setPaymentStatusIdentifier($paymentStatusIdentifier)
    {
        $this->paymentStatusIdentifier = $paymentStatusIdentifier;
    }

    /**
     * @return string
     */
    public function getPaymentMethodIdentifier()
    {
        return $this->paymentMethodIdentifier;
    }

    /**
     * @param string $paymentMethodIdentifier
     */
    public function setPaymentMethodIdentifier($paymentMethodIdentifier)
    {
        $this->paymentMethodIdentifier = $paymentMethodIdentifier;
    }

    /**
     * @return string
     */
    public function getShippingProfileIdentifier()
    {
        return $this->shippingProfileIdentifier;
    }

    /**
     * @param string $shippingProfileIdentifier
     */
    public function setShippingProfileIdentifier($shippingProfileIdentifier)
    {
        $this->shippingProfileIdentifier = $shippingProfileIdentifier;
    }

    /**
     * @return Comment[]
     */
    public function getComments()
    {
        return $this->comments;
    }

    /**
     * @param Comment[] $comments
     */
    public function setComments($comments)
    {
        $this->comments = $comments;
    }

    /**
     * @return Package[]
     */
    public function getPackages()
    {
        return $this->packages;
    }

    /**
     * @param Package[] $packages
     */
    public function setPackages($packages)
    {
        $this->packages = $packages;
    }

    /**
     * @return Attribute[]
     */
    public function getAttributes()
    {
        return $this->attributes;
    }

    /**
     * @param Attribute[] $attributes
     */
    public function setAttributes(array $attributes)
    {
        $this->attributes = $attributes;
    }

    /**
     * {@inheritdoc}
     */
    public function getClassProperties()
    {
        return [
            'identifier' => $this->getIdentifier(),
            'orderNumber' => $this->getOrderNumber(),
            'orderTime' => $this->getOrderTime(),
            'customer' => $this->getCustomer(),
            'billingAddress' => $this->getBillingAddress(),
            'shoppingAddress' => $this->getShippingAddress(),
            'orderItems' => $this->getOrderItems(),
            'shopIdentifier' => $this->getShopIdentifier(),
            'currentyIdentifier' => $this->getCurrencyIdentifier(),
            'orderStatusIdentifier' => $this->getOrderStatusIdentifier(),
            'paymentStatusIdentifier' => $this->getPaymentStatusIdentifier(),
            'paymentMethodIdentifier' => $this->getPaymentMethodIdentifier(),
            'shippingProfileIdentifier' => $this->getShippingProfileIdentifier(),
            'comments' => $this->getComments(),
            'packages' => $this->getPackages(),
            'attributes' => $this->getAttributes(),
        ];
    }
}


<?php

namespace PlentyConnector\Components\CustomProducts\ShopwareAdapter\ResponseParser\Order;

use Shopware\Components\Model\ModelManager;
use ShopwareAdapter\ResponseParser\OrderItem\OrderItemResponseParser;
use ShopwareAdapter\ResponseParser\OrderItem\OrderItemResponseParserInterface;
use SwagCustomProducts\Models\Option;
use SwagCustomProducts\Models\Value;
use SystemConnector\TransferObject\Order\OrderItem\OrderItem;

class DecoratedOrderItemResponseParser implements OrderItemResponseParserInterface
{
    /**
     * @var OrderItemResponseParserInterface
     */
    private $parentOrderItemResponseParser;

    /**
     * @var ModelManager
     */
    private $modelManager;

    /**
     * DecoratedOrderItemResponseParser constructor.
     *
     * @param OrderItemResponseParserInterface $parentOrderItemResponseParser
     * @param ModelManager                     $modelManager
     */
    public function __construct(
        OrderItemResponseParserInterface $parentOrderItemResponseParser,
        ModelManager $modelManager
    ) {
        $this->parentOrderItemResponseParser = $parentOrderItemResponseParser;
        $this->modelManager = $modelManager;
    }

    /**
     * {@inheritdoc}
     */
    public function parse(array $entry, $taxFree = false)
    {
        if (OrderItemResponseParser::ITEM_TYPE_ID_SURCHARGE === $entry['mode']) {
            if (null !== $this->modelManager->getRepository(Value::class)->findOneBy(['ordernumber' => $entry['articleNumber']]) ||
                null !== $this->modelManager->getRepository(Option::class)->findOneBy(['ordernumber' => $entry['articleNumber']])
            ) {
                $entry['mode'] = OrderItem::TYPE_PRODUCT;
            }
        }

        return $this->parentOrderItemResponseParser->parse($entry, $taxFree);
    }
}


<?php

namespace PlentyConnector\Components\Bundle\ShopwareAdapter\CommandHandler;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use PlentyConnector\Components\Bundle\Helper\BundleHelper;
use PlentyConnector\Components\Bundle\TransferObject\Bundle;
use Psr\Log\LoggerInterface;
use ShopwareAdapter\ShopwareAdapter;
use SwagBundle\Models\Bundle as BundleModel;
use SystemConnector\IdentityService\IdentityServiceInterface;
use SystemConnector\IdentityService\Struct\Identity;
use SystemConnector\ServiceBus\Command\CommandInterface;
use SystemConnector\ServiceBus\Command\TransferObjectCommand;
use SystemConnector\ServiceBus\CommandHandler\CommandHandlerInterface;
use SystemConnector\ServiceBus\CommandType;

class RemoveBundleCommandHandler implements CommandHandlerInterface
{
    /**
     * @var IdentityServiceInterface
     */
    private $identityService;

    /**
     * @var EntityManagerInterface
     */
    private $entityManager;

    /**
     * @var BundleHelper
     */
    private $bundleHelper;

    /**
     * @var LoggerInterface
     */
    private $logger;

    public function __construct(
        IdentityServiceInterface $identityService,
        EntityManagerInterface $entityManager,
        BundleHelper $bundleHelper,
        LoggerInterface $logger
    ) {
        $this->identityService = $identityService;
        $this->entityManager = $entityManager;
        $this->bundleHelper = $bundleHelper;
        $this->logger = $logger;
    }

    /**
     * {@inheritdoc}
     */
    public function supports(CommandInterface $command)
    {
        return $command instanceof TransferObjectCommand &&
            $command->getAdapterName() === ShopwareAdapter::NAME &&
            $command->getObjectType() === Bundle::TYPE &&
            $command->getCommandType() === CommandType::REMOVE;
    }

    /**
     * {@inheritdoc}
     *
     * @param TransferObjectCommand $command
     */
    public function handle(CommandInterface $command)
    {
        $identifier = $command->getPayload();

        $this->bundleHelper->registerBundleModels();

        $identity = $this->identityService->findOneBy([
            'objectIdentifier' => (string) $identifier,
            'objectType' => Bundle::TYPE,
            'adapterName' => ShopwareAdapter::NAME,
        ]);

        if (null === $identity) {
            $this->logger->notice('no matching identity found', ['command' => $command]);

            return false;
        }

        /**
         * @var EntityRepository $repository
         */
        $repository = $this->entityManager->getRepository(BundleModel::class);

        /**
         * @var BundleModel $bundleModel
         */
        $bundleModel = $repository->find($identity->getAdapterIdentifier());

        if (null === $bundleModel) {
            $this->logger->notice('identity removed but the object was not found', ['command' => $command]);

            return false;
        }

        $this->entityManager->remove($bundleModel);
        $this->entityManager->flush();

        $identities = $this->identityService->findBy([
            'objectIdentifier' => $identifier,
        ]);

        array_walk($identities, function (Identity $identity) {
            $this->identityService->remove($identity);
        });

        return true;
    }
}


<?php

namespace SystemConnector\Console\Command;

use Exception;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use SystemConnector\Console\OutputHandler\OutputHandlerInterface;
use SystemConnector\Logger\ConsoleHandler;
use SystemConnector\MappingService\MappingServiceInterface;
use SystemConnector\TransferObject\TransferObjectInterface;
use Throwable;

class MappingCommand extends Command
{
    /**
     * @var MappingServiceInterface
     */
    private $mappingService;

    /**
     * @var OutputHandlerInterface
     */
    private $outputHandler;

    /**
     * @var LoggerInterface
     */
    private $logger;

    public function __construct(
        MappingServiceInterface $mappingService,
        OutputHandlerInterface $outputHandler,
        LoggerInterface $logger
    ) {
        $this->mappingService = $mappingService;
        $this->outputHandler = $outputHandler;
        $this->logger = $logger;

        parent::__construct();
    }

    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this->setName('plentyconnector:mapping');
        $this->setDescription('displays mapping informations');
        $this->addArgument(
            'objectType',
            InputArgument::OPTIONAL,
            'Object type to process. Leave empty for every object type'
        );
    }

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        if (method_exists($this->logger, 'pushHandler')) {
            $this->logger->pushHandler(new ConsoleHandler($output));
        }

        $this->outputHandler->initialize($input, $output);

        $objectType = $input->getArgument('objectType');

        try {
            $mapping = $this->mappingService->getMappingInformation($objectType);

            foreach ($mapping as $entry) {
                $this->outputHandler->writeLine($entry->getObjectType());

                $headers = [
                    $entry->getOriginAdapterName(),
                    $entry->getDestinationAdapterName(),
                ];

                $rows = [];
                foreach ($entry->getOriginTransferObjects() as $object) {
                    $targetIdentifier = array_filter($entry->getDestinationTransferObjects(), function (TransferObjectInterface $targetObject) use ($object) {
                        return $object->getIdentifier() === $targetObject->getIdentifier();
                    });

                    if (!empty($targetIdentifier)) {
                        $targetIdentifier = array_shift($targetIdentifier);

                        if (method_exists($targetIdentifier, 'getName')) {
                            $targetIdentifier = $targetIdentifier->getName();
                        } else {
                            $targetIdentifier = $targetIdentifier->getIdentifier();
                        }
                    } else {
                        $targetIdentifier = '';
                    }

                    if (method_exists($object, 'getName')) {
                        $objectIdentifier = $object->getName();
                    } else {
                        $objectIdentifier = $object->getIdentifier();
                    }

                    $rows[] = [
                        $objectIdentifier,
                        $targetIdentifier,
                    ];
                }

                $this->outputHandler->createTable($headers, $rows);
            }
        } catch (Exception $exception) {
            $this->logger->error($exception->getMessage());
        } catch (Throwable $exception) {
            $this->logger->error($exception->getMessage());
        }
    }
}


<?php

namespace PlentymarketsAdapter\ServiceBus\QueryHandler\Language;

use PlentymarketsAdapter\Helper\LanguageHelperInterface;
use PlentymarketsAdapter\PlentymarketsAdapter;
use PlentymarketsAdapter\ResponseParser\Language\LanguageResponseParserInterface;
use SystemConnector\ServiceBus\Query\FetchTransferObjectQuery;
use SystemConnector\ServiceBus\Query\QueryInterface;
use SystemConnector\ServiceBus\QueryHandler\QueryHandlerInterface;
use SystemConnector\ServiceBus\QueryType;
use SystemConnector\TransferObject\Language\Language;

class FetchAllLanguagesQueryHandler implements QueryHandlerInterface
{
    /**
     * @var LanguageResponseParserInterface
     */
    private $responseParser;

    /**
     * @var LanguageHelperInterface
     */
    private $languageHelper;

    public function __construct(
        LanguageResponseParserInterface $responseParser,
        LanguageHelperInterface $languageHelper
    ) {
        $this->responseParser = $responseParser;
        $this->languageHelper = $languageHelper;
    }

    /**
     * {@inheritdoc}
     */
    public function supports(QueryInterface $query)
    {
        return $query instanceof FetchTransferObjectQuery &&
            $query->getAdapterName() === PlentymarketsAdapter::NAME &&
            $query->getObjectType() === Language::TYPE &&
            $query->getQueryType() === QueryType::ALL;
    }

    /**
     * {@inheritdoc}
     */
    public function handle(QueryInterface $query)
    {
        $elements = $this->languageHelper->getLanguages();

        foreach ($elements as $element) {
            $result = $this->responseParser->parse($element);

            if (null === $result) {
                continue;
            }

            yield $result;
        }
    }
}


<?php

namespace PlentymarketsAdapter\ResponseParser\OrderStatus;

use PlentymarketsAdapter\PlentymarketsAdapter;
use SystemConnector\IdentityService\IdentityServiceInterface;
use SystemConnector\TransferObject\OrderStatus\OrderStatus;

class OrderStatusResponseParser implements OrderStatusResponseParserInterface
{
    /**
     * @var IdentityServiceInterface
     */
    private $identityService;

    public function __construct(IdentityServiceInterface $identityService)
    {
        $this->identityService = $identityService;
    }

    /**
     * {@inheritdoc}
     */
    public function parse(array $entry)
    {
        if (empty($entry['id'])) {
            $entry['id'] = $entry['statusId'];
        }

        if (empty($entry['id'])) {
            return null;
        }

        $identity = $this->identityService->findOneOrCreate(
            (string) $entry['id'],
            PlentymarketsAdapter::NAME,
            OrderStatus::TYPE
        );

        return OrderStatus::fromArray([
            'identifier' => $identity->getObjectIdentifier(),
            'name' => $this->getName($entry),
        ]);
    }

    /**
     * @param array $entry
     *
     * @return string
     */
    private function getName($entry)
    {
        if (empty($entry['names'])) {
            return $entry['id'];
        }

        $names = $entry['names'];

        if (!empty($names)) {
            return array_shift($names);
        }

        return $entry['id'];
    }
}


<?php

namespace SystemConnector\TransferObject\Order\Customer;

use DateTimeImmutable;
use ReflectionClass;
use SystemConnector\ValueObject\AbstractValueObject;

class Customer extends AbstractValueObject
{
    const TYPE_NORMAL = 'normal';
    const TYPE_GUEST = 'guest';

    const GENDER_MALE = 'male';
    const GENDER_FEMALE = 'female';

    /**
     * @var int
     */
    private $type = self::TYPE_NORMAL;

    /**
     * @var string
     */
    private $number = '';

    /**
     * @var string
     */
    private $email = '';

    /**
     * @var bool
     */
    private $newsletter = false;

    /**
     * @var null|DateTimeImmutable
     */
    private $newsletterAgreementDate;

    /**
     * @var string
     */
    private $languageIdentifier = '';

    /**
     * @var string
     */
    private $customerGroupIdentifier = '';

    /**
     * @var string
     */
    private $gender = self::GENDER_MALE;

    /**
     * @var null|string
     */
    private $title;

    /**
     * @var string
     */
    private $firstname = '';

    /**
     * @var string
     */
    private $lastname = '';

    /**
     * @var null|DateTimeImmutable
     */
    private $birthday;

    /**
     * @var null|string
     */
    private $phoneNumber;

    /**
     * @var null|string
     */
    private $mobilePhoneNumber;

    /**
     * @var string
     */
    private $shopIdentifier = '';

    public function __construct()
    {
        $this->birthday = new DateTimeImmutable('now');
    }

    /**
     * @return array
     */
    public function getCustomerTypes()
    {
        return $this->getConstantsByName('TYPE');
    }

    /**
     * @return int
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * @param int $type
     */
    public function setType($type)
    {
        $this->type = $type;
    }

    /**
     * @return string
     */
    public function getNumber()
    {
        return $this->number;
    }

    /**
     * @param string $number
     */
    public function setNumber($number)
    {
        $this->number = $number;
    }

    /**
     * @return string
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * @param string $email
     */
    public function setEmail($email)
    {
        $this->email = $email;
    }

    /**
     * @return bool
     */
    public function getNewsletter()
    {
        return $this->newsletter;
    }

    /**
     * @param bool $newsletter
     */
    public function setNewsletter($newsletter)
    {
        $this->newsletter = $newsletter;
    }

    /**
     * @return null|DateTimeImmutable
     */
    public function getNewsletterAgreementDate()
    {
        return $this->newsletterAgreementDate;
    }

    /**
     * @param null|DateTimeImmutable $newsletterAgreementDate
     */
    public function setNewsletterAgreementDate(DateTimeImmutable $newsletterAgreementDate = null)
    {
        $this->newsletterAgreementDate = $newsletterAgreementDate;
    }

    /**
     * @return string
     */
    public function getLanguageIdentifier()
    {
        return $this->languageIdentifier;
    }

    /**
     * @param string $languageIdentifier
     */
    public function setLanguageIdentifier($languageIdentifier)
    {
        $this->languageIdentifier = $languageIdentifier;
    }

    /**
     * @return string
     */
    public function getCustomerGroupIdentifier()
    {
        return $this->customerGroupIdentifier;
    }

    /**
     * @param string $customerGroupIdentifier
     */
    public function setCustomerGroupIdentifier($customerGroupIdentifier)
    {
        $this->customerGroupIdentifier = $customerGroupIdentifier;
    }

    /**
     * @return string
     */
    public function getGender()
    {
        return $this->gender;
    }

    /**
     * @param string $gender
     */
    public function setGender($gender)
    {
        $this->gender = $gender;
    }

    /**
     * @return array
     */
    public function getGenders()
    {
        return $this->getConstantsByName('GENDER');
    }

    /**
     * @return null|string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param null|string $title
     */
    public function setTitle($title = null)
    {
        $this->title = $title;
    }

    /**
     * @return null|string
     */
    public function getFirstname()
    {
        return $this->firstname;
    }

    /**
     * @param null|string $firstname
     */
    public function setFirstname($firstname = null)
    {
        $this->firstname = $firstname;
    }

    /**
     * @return null|string
     */
    public function getLastname()
    {
        return $this->lastname;
    }

    /**
     * @param null|string $lastname
     */
    public function setLastname($lastname)
    {
        $this->lastname = $lastname;
    }

    /**
     * @return null|DateTimeImmutable
     */
    public function getBirthday()
    {
        return $this->birthday;
    }

    /**
     * @param null|DateTimeImmutable $birthday
     */
    public function setBirthday(DateTimeImmutable $birthday = null)
    {
        $this->birthday = $birthday;
    }

    /**
     * @return null|string
     */
    public function getPhoneNumber()
    {
        return $this->phoneNumber;
    }

    /**
     * @param null|string $phoneNumber
     */
    public function setPhoneNumber($phoneNumber = null)
    {
        $this->phoneNumber = $phoneNumber;
    }

    /**
     * @return null|string
     */
    public function getMobilePhoneNumber()
    {
        return $this->mobilePhoneNumber;
    }

    /**
     * @param null|string $mobilePhoneNumber
     */
    public function setMobilePhoneNumber($mobilePhoneNumber = null)
    {
        $this->mobilePhoneNumber = $mobilePhoneNumber;
    }

    /**
     * @return string
     */
    public function getShopIdentifier()
    {
        return $this->shopIdentifier;
    }

    /**
     * @param string $shopIdentifier
     */
    public function setShopIdentifier($shopIdentifier)
    {
        $this->shopIdentifier = $shopIdentifier;
    }

    /**
     * {@inheritdoc}
     */
    public function getClassProperties()
    {
        return [
            'type' => $this->getType(),
            'number' => $this->getNumber(),
            'email' => $this->getEmail(),
            'newsletter' => $this->getNewsletter(),
            'newsletterAgreementDate' => $this->getNewsletterAgreementDate(),
            'languageIdentifier' => $this->getLanguageIdentifier(),
            'customerGroupIdentifier' => $this->getCustomerGroupIdentifier(),
            'gender' => $this->getGender(),
            'title' => $this->getTitle(),
            'firstname' => $this->getFirstname(),
            'lastname' => $this->getLastname(),
            'birthday' => $this->getBirthday(),
            'phoneNumber' => $this->getPhoneNumber(),
            'mobilePhoneNumber' => $this->getMobilePhoneNumber(),
            'shopIdentifier' => $this->getShopIdentifier(),
        ];
    }

    /**
     * @param string $name
     *
     * @return array
     */
    private function getConstantsByName($name)
    {
        $reflection = new ReflectionClass(__CLASS__);

        $constants = $reflection->getConstants();

        $result = [];

        foreach ($constants as $key => $constant) {
            if (false !== stripos($key, $name)) {
                $result[$key] = $constant;
            }
        }

        return $result;
    }
}


<?php

namespace SystemConnector\TransferObject\Category;

use SystemConnector\TransferObject\AbstractTransferObject;
use SystemConnector\TransferObject\AttributableInterface;
use SystemConnector\TransferObject\TranslateableInterface;
use SystemConnector\ValueObject\Attribute\Attribute;
use SystemConnector\ValueObject\Translation\Translation;

class Category extends AbstractTransferObject implements TranslateableInterface, AttributableInterface
{
    const TYPE = 'Category';

    /**
     * @var string
     */
    private $identifier = '';

    /**
     * @var string
     */
    private $name = '';

    /**
     * @var bool
     */
    private $active = false;

    /**
     * @var null|string
     */
    private $parentIdentifier;

    /**
     * @var array
     */
    private $shopIdentifiers = [];

    /**
     * @var array
     */
    private $imageIdentifiers = [];

    /**
     * @var int
     */
    private $position = 0;

    /**
     * @var string
     */
    private $description = '';

    /**
     * @var string
     */
    private $longDescription = '';

    /**
     * @var string
     */
    private $metaTitle = '';

    /**
     * @var string
     */
    private $metaDescription = '';

    /**
     * @var string
     */
    private $metaKeywords = '';

    /**
     * @var string
     */
    private $metaRobots = '';

    /**
     * @var Translation[]
     */
    private $translations = [];

    /**
     * @var Attribute[]
     */
    private $attributes = [];

    /**
     * {@inheritdoc}
     */
    public function getType()
    {
        return self::TYPE;
    }

    /**
     * {@inheritdoc}
     */
    public function getIdentifier()
    {
        return $this->identifier;
    }

    /**
     * {@inheritdoc}
     */
    public function setIdentifier($identifier)
    {
        $this->identifier = $identifier;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param string $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @return bool
     */
    public function getActive()
    {
        return $this->active;
    }

    /**
     * @param bool $active
     */
    public function setActive($active)
    {
        $this->active = $active;
    }

    /**
     * @return null|string
     */
    public function getParentIdentifier()
    {
        return $this->parentIdentifier;
    }

    /**
     * @param string $parentIdentifier
     */
    public function setParentIdentifier($parentIdentifier)
    {
        $this->parentIdentifier = $parentIdentifier;
    }

    /**
     * @return array
     */
    public function getShopIdentifiers()
    {
        return $this->shopIdentifiers;
    }

    /**
     * @param array $shopIdentifiers
     */
    public function setShopIdentifiers(array $shopIdentifiers = [])
    {
        $this->shopIdentifiers = $shopIdentifiers;
    }

    /**
     * @return array
     */
    public function getImageIdentifiers()
    {
        return $this->imageIdentifiers;
    }

    /**
     * @param array $imageIdentifiers
     */
    public function setImageIdentifiers(array $imageIdentifiers)
    {
        $this->imageIdentifiers = $imageIdentifiers;
    }

    /**
     * @return int
     */
    public function getPosition()
    {
        return $this->position;
    }

    /**
     * @param null|int $position
     */
    public function setPosition($position = null)
    {
        if (null === $position) {
            $position = 0;
        }

        $this->position = $position;
    }

    /**
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * @param string $description
     */
    public function setDescription($description)
    {
        $this->description = $description;
    }

    /**
     * @return string
     */
    public function getLongDescription()
    {
        return $this->longDescription;
    }

    /**
     * @param string $longDescription
     */
    public function setLongDescription($longDescription)
    {
        $this->longDescription = $longDescription;
    }

    /**
     * @return string
     */
    public function getMetaTitle()
    {
        return $this->metaTitle;
    }

    /**
     * @param string $metaTitle
     */
    public function setMetaTitle($metaTitle)
    {
        $this->metaTitle = $metaTitle;
    }

    /**
     * @return string
     */
    public function getMetaDescription()
    {
        return $this->metaDescription;
    }

    /**
     * @param string $metaDescription
     */
    public function setMetaDescription($metaDescription)
    {
        $this->metaDescription = $metaDescription;
    }

    /**
     * @return string
     */
    public function getMetaKeywords()
    {
        return $this->metaKeywords;
    }

    /**
     * @param string $metaKeywords
     */
    public function setMetaKeywords($metaKeywords)
    {
        $this->metaKeywords = $metaKeywords;
    }

    /**
     * @return string
     */
    public function getMetaRobots()
    {
        return $this->metaRobots;
    }

    /**
     * @param string $metaRobots
     */
    public function setMetaRobots($metaRobots)
    {
        $this->metaRobots = $metaRobots;
    }

    /**
     * @return Translation[]
     */
    public function getTranslations()
    {
        return $this->translations;
    }

    /**
     * @param Translation[] $translations
     */
    public function setTranslations(array $translations)
    {
        $this->translations = $translations;
    }

    /**
     * @return Attribute[]
     */
    public function getAttributes()
    {
        return $this->attributes;
    }

    /**
     * @param Attribute[] $attributes
     */
    public function setAttributes(array $attributes)
    {
        $this->attributes = $attributes;
    }

    /**
     * {@inheritdoc}
     */
    public function getClassProperties()
    {
        return [
            'identifier' => $this->getIdentifier(),
            'name' => $this->getName(),
            'active' => $this->getActive(),
            'parentIdentifiers' => $this->getParentIdentifier(),
            'shopIdentifiers' => $this->getShopIdentifiers(),
            'imageIdentifiers' => $this->getImageIdentifiers(),
            'position' => $this->getPosition(),
            'description' => $this->getDescription(),
            'longDescription' => $this->getLongDescription(),
            'metaTitle' => $this->getMetaTitle(),
            'metaDescription' => $this->getMetaDescription(),
            'metaKeywords' => $this->getMetaKeywords(),
            'metaRobots' => $this->getMetaRobots(),
            'translations' => $this->getTranslations(),
            'attributes' => $this->getAttributes(),
        ];
    }
}


<?php

namespace PlentyConnector\Components\PayPal\PaymentData;

use DateTimeImmutable;
use SystemConnector\TransferObject\Payment\PaymentData\PaymentDataInterface;
use SystemConnector\ValueObject\AbstractValueObject;

class PayPalPlusInvoicePaymentData extends AbstractValueObject implements PaymentDataInterface
{
    /**
     * @var string
     */
    private $reference_number;

    /**
     * @var string
     */
    private $instruction_type;

    /**
     * @var string
     */
    private $bank_name;

    /**
     * @var string
     */
    private $account_holder_name;

    /**
     * @var string
     */
    private $international_bank_account_number;

    /**
     * @var string
     */
    private $bank_identifier_code;

    /**
     * @var float
     */
    private $amount_value;

    /**
     * @var string
     */
    private $amount_currency;

    /**
     * @var DateTimeImmutable
     */
    private $payment_due_date;

    /**
     * @return string
     */
    public function getReferenceNumber()
    {
        return $this->reference_number;
    }

    /**
     * @param string $reference_number
     */
    public function setReferenceNumber($reference_number)
    {
        $this->reference_number = $reference_number;
    }

    /**
     * @return string
     */
    public function getInstructionType()
    {
        return $this->instruction_type;
    }

    /**
     * @param string $instruction_type
     */
    public function setInstructionType($instruction_type)
    {
        $this->instruction_type = $instruction_type;
    }

    /**
     * @return string
     */
    public function getBankName()
    {
        return $this->bank_name;
    }

    /**
     * @param string $bank_name
     */
    public function setBankName($bank_name)
    {
        $this->bank_name = $bank_name;
    }

    /**
     * @return string
     */
    public function getAccountHolderName()
    {
        return $this->account_holder_name;
    }

    /**
     * @param string $account_holder_name
     */
    public function setAccountHolderName($account_holder_name)
    {
        $this->account_holder_name = $account_holder_name;
    }

    /**
     * @return string
     */
    public function getInternationalBankAccountNumber()
    {
        return $this->international_bank_account_number;
    }

    /**
     * @param string $international_bank_account_number
     */
    public function setInternationalBankAccountNumber($international_bank_account_number)
    {
        $this->international_bank_account_number = $international_bank_account_number;
    }

    /**
     * @return string
     */
    public function getBankIdentifierCode()
    {
        return $this->bank_identifier_code;
    }

    /**
     * @param string $bank_identifier_code
     */
    public function setBankIdentifierCode($bank_identifier_code)
    {
        $this->bank_identifier_code = $bank_identifier_code;
    }

    /**
     * @return float
     */
    public function getAmountValue()
    {
        return $this->amount_value;
    }

    /**
     * @param float $amount_value
     */
    public function setAmountValue($amount_value)
    {
        $this->amount_value = $amount_value;
    }

    /**
     * @return string
     */
    public function getAmountCurrency()
    {
        return $this->amount_currency;
    }

    /**
     * @param string $amount_currency
     */
    public function setAmountCurrency($amount_currency)
    {
        $this->amount_currency = $amount_currency;
    }

    /**
     * @return DateTimeImmutable
     */
    public function getPaymentDueDate()
    {
        return $this->payment_due_date;
    }

    /**
     * @param DateTimeImmutable $payment_due_date
     */
    public function setPaymentDueDate(DateTimeImmutable $payment_due_date)
    {
        $this->payment_due_date = $payment_due_date;
    }

    /**
     * {@inheritdoc}
     */
    public function getClassProperties()
    {
        return [
            'reference_number' => $this->getReferenceNumber(),
            'instruction_type' => $this->getInstructionType(),
            'bank_name' => $this->getBankName(),
            'account_holder_name' => $this->getAccountHolderName(),
            'international_bank_account_number' => $this->getInternationalBankAccountNumber(),
            'bank_identifier_code' => $this->getBankIdentifierCode(),
            'amountValue' => $this->getAmountValue(),
            'amount_currency' => $this->getAmountCurrency(),
            'payment_due_date' => $this->getPaymentDueDate(),
        ];
    }
}


<?php

namespace PlentymarketsAdapter\RequestGenerator\Order\Customer;

use PlentymarketsAdapter\PlentymarketsAdapter;
use SystemConnector\IdentityService\Exception\NotFoundException;
use SystemConnector\IdentityService\IdentityServiceInterface;
use SystemConnector\TransferObject\CustomerGroup\CustomerGroup;
use SystemConnector\TransferObject\Language\Language;
use SystemConnector\TransferObject\Order\Customer\Customer;
use SystemConnector\TransferObject\Order\Order;
use SystemConnector\TransferObject\Shop\Shop;

class CustomerRequestGenerator implements CustomerRequestGeneratorInterface
{
    /**
     * @var IdentityServiceInterface
     */
    private $identityService;

    public function __construct(IdentityServiceInterface $identityService)
    {
        $this->identityService = $identityService;
    }

    /**
     * {@inheritdoc}
     */
    public function generate(Customer $customer, Order $order)
    {
        $shopIdentity = $this->identityService->findOneBy([
            'objectIdentifier' => $order->getShopIdentifier(),
            'objectType' => Shop::TYPE,
            'adapterName' => PlentymarketsAdapter::NAME,
        ]);

        if (null === $shopIdentity) {
            throw new NotFoundException('shop not mapped - ' . $order->getShopIdentifier());
        }

        $languageIdentity = $this->identityService->findOneBy([
            'objectIdentifier' => $customer->getLanguageIdentifier(),
            'objectType' => Language::TYPE,
            'adapterName' => PlentymarketsAdapter::NAME,
        ]);

        if (null === $languageIdentity) {
            throw new NotFoundException('language not found - ' . $customer->getLanguageIdentifier());
        }

        $customerGroupIdentitiy = $this->identityService->findOneBy([
            'objectIdentifier' => $customer->getCustomerGroupIdentifier(),
            'objectType' => CustomerGroup::TYPE,
            'adapterName' => PlentymarketsAdapter::NAME,
        ]);

        $customerParams = [
            'number' => $customer->getNumber(),
            'typeId' => 1,
            'firstName' => $customer->getFirstname(),
            'lastName' => $customer->getLastname(),
            'gender' => $customer->getGender() === Customer::GENDER_MALE ? 'male' : 'female',
            'lang' => $languageIdentity->getAdapterIdentifier(),
            'singleAccess' => $customer->getType() === Customer::TYPE_GUEST,
            'plentyId' => $shopIdentity->getAdapterIdentifier(),
            'newsletterAllowanceAt' => '',
            'lastOrderAt' => $order->getOrderTime()->format(DATE_W3C),
            'options' => [],
            'referrerId' => 1,
        ];

        if (null !== $customerGroupIdentitiy) {
            $customerParams['classId'] = (int) $customerGroupIdentitiy->getAdapterIdentifier();
        }

        if (null !== $customer->getBirthday()) {
            $customerParams['birthdayAt'] = $customer->getBirthday()->format(DATE_W3C);
        }

        if ($customer->getNewsletter()) {
            if (null !== $customer->getNewsletterAgreementDate()) {
                $customerParams['newsletterAllowanceAt'] = $customer->getNewsletterAgreementDate()->format(DATE_W3C);
            } else {
                $customerParams['newsletterAllowanceAt'] = $order->getOrderTime()->format(DATE_W3C);
            }
        }

        if (null !== $customer->getPhoneNumber()) {
            $customerParams['options'][] = [
                'typeId' => 1,
                'subTypeId' => 4,
                'value' => $customer->getPhoneNumber(),
                'priority' => 0,
            ];
        }

        if (null !== $customer->getMobilePhoneNumber()) {
            $customerParams['options'][] = [
                'typeId' => 1,
                'subTypeId' => 2,
                'value' => $customer->getMobilePhoneNumber(),
                'priority' => 0,
            ];
        }

        if (!empty($customer->getEmail())) {
            $customerParams['options'][] = [
                'typeId' => 2,
                'subTypeId' => 4,
                'value' => $customer->getEmail(),
                'priority' => 0,
            ];
        }

        return $customerParams;
    }
}


<?php

namespace PlentymarketsAdapter\RequestGenerator\Order;

use PlentymarketsAdapter\Client\ClientInterface;
use PlentymarketsAdapter\PlentymarketsAdapter;
use PlentymarketsAdapter\RequestGenerator\Order\Address\AddressRequestGeneratorInterface;
use PlentymarketsAdapter\RequestGenerator\Order\Customer\CustomerRequestGeneratorInterface;
use PlentymarketsAdapter\RequestGenerator\Order\OrderItem\OrderItemRequestGeneratorInterface;
use SystemConnector\IdentityService\Exception\NotFoundException;
use SystemConnector\IdentityService\IdentityServiceInterface;
use SystemConnector\TransferObject\Language\Language;
use SystemConnector\TransferObject\Order\Address\Address;
use SystemConnector\TransferObject\Order\Customer\Customer;
use SystemConnector\TransferObject\Order\Order;
use SystemConnector\TransferObject\Order\OrderItem\OrderItem;
use SystemConnector\TransferObject\PaymentMethod\PaymentMethod;
use SystemConnector\TransferObject\ShippingProfile\ShippingProfile;
use SystemConnector\TransferObject\Shop\Shop;

class OrderRequestGenerator implements OrderRequestGeneratorInterface
{
    /**
     * @var IdentityServiceInterface
     */
    private $identityService;

    /**
     * @var ClientInterface
     */
    private $client;

    /**
     * @var OrderItemRequestGeneratorInterface
     */
    private $orderItemRequestGenerator;

    /**
     * @var CustomerRequestGeneratorInterface
     */
    private $customerRequestGenerator;

    /**
     * @var AddressRequestGeneratorInterface
     */
    private $addressReuqestGenerator;

    public function __construct(
        IdentityServiceInterface $identityService,
        ClientInterface $client,
        OrderItemRequestGeneratorInterface $orderItemRequestGenerator,
        CustomerRequestGeneratorInterface $customerRequestGenerator,
        AddressRequestGeneratorInterface $addressReuqestGenerator
    ) {
        $this->identityService = $identityService;
        $this->client = $client;
        $this->orderItemRequestGenerator = $orderItemRequestGenerator;
        $this->customerRequestGenerator = $customerRequestGenerator;
        $this->addressReuqestGenerator = $addressReuqestGenerator;
    }

    /**
     * {@inheritdoc}
     */
    public function generate(Order $order)
    {
        $shopIdentity = $this->identityService->findOneBy([
            'objectIdentifier' => $order->getShopIdentifier(),
            'objectType' => Shop::TYPE,
            'adapterName' => PlentymarketsAdapter::NAME,
        ]);

        if (null === $shopIdentity) {
            throw new NotFoundException('shop not mapped');
        }

        $languageIdentity = $this->identityService->findOneBy([
            'objectIdentifier' => $order->getCustomer()->getLanguageIdentifier(),
            'objectType' => Language::TYPE,
            'adapterName' => PlentymarketsAdapter::NAME,
        ]);

        if (null === $languageIdentity) {
            throw new NotFoundException('language not mapped');
        }

        $params = [
            'typeId' => 1,
            'plentyId' => $shopIdentity->getAdapterIdentifier(),
        ];

        $plentyCustomer = $this->handleCustomer($order);

        $params['relations'] = [
            [
                'referenceType' => 'contact',
                'referenceId' => $plentyCustomer['id'],
                'relation' => 'receiver',
            ],
        ];

        $params['addressRelations'] = [];

        $billingAddress = $this->createAddress($order->getBillingAddress(), $order, $plentyCustomer);
        if (!empty($billingAddress)) {
            $params['addressRelations'][] = [
                'typeId' => 1,
                'addressId' => $billingAddress['id'],
            ];
        }

        $shippingAddress = $this->createAddress($order->getShippingAddress(), $order, $plentyCustomer, 2);
        if (!empty($shippingAddress)) {
            $params['addressRelations'][] = [
                'typeId' => 2,
                'addressId' => $shippingAddress['id'],
            ];
        }

        $paymentMethodIdentity = $this->identityService->findOneBy([
            'objectIdentifier' => $order->getPaymentMethodIdentifier(),
            'objectType' => PaymentMethod::TYPE,
            'adapterName' => PlentymarketsAdapter::NAME,
        ]);

        if (null === $paymentMethodIdentity) {
            throw new NotFoundException('missing payment method mapping');
        }

        $shippingProfileIdentity = $this->identityService->findOneBy([
            'objectIdentifier' => $order->getShippingProfileIdentifier(),
            'objectType' => ShippingProfile::TYPE,
            'adapterName' => PlentymarketsAdapter::NAME,
        ]);

        if (null === $shippingProfileIdentity) {
            throw new NotFoundException('shipping profile not mapped');
        }

        $params['properties'] = [
            [
                'typeId' => 6,
                'value' => (string) $languageIdentity->getAdapterIdentifier(),
            ],
            [
                'typeId' => 7,
                'value' => (string) $order->getOrderNumber(),
            ],
            [
                'typeId' => 3,
                'value' => (string) $paymentMethodIdentity->getAdapterIdentifier(),
            ],
            [
                'typeId' => 2,
                'value' => (string) $shippingProfileIdentity->getAdapterIdentifier(),
            ],
        ];

        $vouchers = array_filter($order->getOrderItems(), function (OrderItem $item) {
            return $item->getType() === OrderItem::TYPE_VOUCHER;
        });

        $voucher = null;
        if (!empty($vouchers)) {
            /**
             * @var OrderItem $voucher
             */
            $voucher = array_shift($vouchers);
        }

        if (null !== $voucher) {
            $params['properties'][] = [
                'typeId' => 18,
                'value' => (string) $voucher->getNumber(),
            ];

            $params['properties'][] = [
                'typeId' => 19,
                'value' => 'fixed',
            ];
        }

        $params['dates'] = [
            [
                'typeId' => 2,
                'date' => $order->getOrderTime()->format(DATE_W3C),
            ],
        ];

        $params['orderItems'] = [];
        foreach ($order->getOrderItems() as $orderItem) {
            $params['orderItems'][] = $this->orderItemRequestGenerator->generate($orderItem, $order);
        }

        return $params;
    }

    /**
     * @param Address $address
     * @param Order   $order
     * @param array   $plentyCustomer
     * @param int     $addressType
     *
     * @return array
     */
    private function createAddress(Address $address, Order $order, array $plentyCustomer, $addressType = 1)
    {
        $params = $this->addressReuqestGenerator->generate($address, $order, $addressType);

        return $this->client->request('POST', 'accounts/contacts/' . $plentyCustomer['id'] . '/addresses', $params);
    }

    /**
     * @param string $mail
     *
     * @return null|array
     */
    private function findCustomer($mail)
    {
        $customerResult = $this->client->request('GET', 'accounts/contacts', [
            'contactEmail' => $mail,
        ]);

        if (empty($customerResult)) {
            return null;
        }

        $possibleCustomers = array_filter($customerResult, function ($entry) {
            return $entry['singleAccess'] !== '1';
        });

        if (empty($possibleCustomers)) {
            return null;
        }

        return array_shift($possibleCustomers);
    }

    /**
     * @param Order $order
     *
     * @return array|bool|mixed
     */
    private function handleCustomer(Order $order)
    {
        $customer = $order->getCustomer();

        $plentyCustomer = false;

        if ($customer->getType() === Customer::TYPE_NORMAL) {
            $plentyCustomer = $this->findCustomer($customer->getEmail());
        }

        $customerParams = $this->customerRequestGenerator->generate($customer, $order);

        if (!$plentyCustomer) {
            $plentyCustomer = $this->client->request('POST', 'accounts/contacts', $customerParams);
        } else {
            $this->client->request('PUT', 'accounts/contacts/' . $plentyCustomer['id'], $customerParams);
        }

        return $plentyCustomer;
    }
}


<?php

namespace SystemConnector\BacklogService;

use SystemConnector\BacklogService\Storage\BacklogServiceStorageInterface;
use SystemConnector\ServiceBus\Command\CommandInterface;
use Traversable;

class BacklogService implements BacklogServiceInterface
{
    /**
     * @var BacklogServiceStorageInterface[]|Traversable
     */
    private $storages;

    /**
     * @param BacklogServiceStorageInterface[]|Traversable $storage
     */
    public function __construct(Traversable $storage)
    {
        $this->storages = iterator_to_array($storage);
    }

    /**
     * {@inheritdoc}
     */
    public function enqueue(CommandInterface $command)
    {
        $storage = reset($this->storages);

        $storage->enqueue($command);
    }

    /**
     * {@inheritdoc}
     */
    public function dequeue()
    {
        $storage = reset($this->storages);

        return $storage->dequeue();
    }

    /**
     * {@inheritdoc}
     */
    public function getInfo()
    {
        $storage = reset($this->storages);

        return $storage->getInfo();
    }
}


<?php

namespace ShopwareAdapter\ResponseParser\Country;

use ShopwareAdapter\ShopwareAdapter;
use SystemConnector\IdentityService\IdentityServiceInterface;
use SystemConnector\TransferObject\Country\Country;

class CountryResponseParser implements CountryResponseParserInterface
{
    /**
     * @var IdentityServiceInterface
     */
    private $identityService;

    public function __construct(IdentityServiceInterface $identityService)
    {
        $this->identityService = $identityService;
    }

    /**
     * {@inheritdoc}
     */
    public function parse(array $entry)
    {
        $identity = $this->identityService->findOneOrCreate(
            (string) $entry['id'],
            ShopwareAdapter::NAME,
            Country::TYPE
        );

        return Country::fromArray([
            'identifier' => $identity->getObjectIdentifier(),
            'name' => $entry['name'],
        ]);
    }
}


<?php

namespace PlentyConnector\Components\AmazonPay\Shopware;

use Doctrine\DBAL\Connection;
use Exception;
use PlentyConnector\Components\AmazonPay\PaymentData\AmazonPayPaymentData;
use ShopwareAdapter\ResponseParser\Payment\PaymentResponseParserInterface;
use SystemConnector\ConfigService\ConfigServiceInterface;
use SystemConnector\TransferObject\Payment\Payment;

class AmazonPayPaymentResponseParser implements PaymentResponseParserInterface
{
    /**
     * @var PaymentResponseParserInterface
     */
    private $parentResponseParser;

    /**
     * @var Connection
     */
    private $connection;

    /**
     * @var ConfigServiceInterface
     */
    private $configService;

    public function __construct(
        PaymentResponseParserInterface $parentResponseParser,
        Connection $connection,
        ConfigServiceInterface $configService
    ) {
        $this->parentResponseParser = $parentResponseParser;
        $this->connection = $connection;
        $this->configService = $configService;
    }

    /**
     * {@inheritdoc}
     */
    public function parse(array $element)
    {
        $payments = $this->parentResponseParser->parse($element);

        foreach ($payments as $payment) {
            if (!($payment instanceof Payment)) {
                continue;
            }
            $this->addAmazonPay($payment, $element);
        }

        return $payments;
    }

    /**
     * @param string $ordernumber
     *
     * @return array|bool
     */
    private function getAmazonPayData($ordernumber)
    {
        try {
            $query = 'SELECT * FROM s_order_attributes WHERE orderID = ?';

            return $this->connection->fetchAssoc($query, [$ordernumber]);
        } catch (Exception $exception) {
            return false;
        }
    }

    /**
     * @param Payment $payment
     * @param array   $element
     */
    private function addAmazonPay(Payment $payment, array $element)
    {
        $data = $this->getAmazonPayData($element['id']);

        if (empty($data)) {
            return;
        }

        $paymentData = new AmazonPayPaymentData();
        $paymentData->setTransactionId($element['transactionId']);
        $paymentData->setKey($this->configService->get('rest_password'));

        $payment->setPaymentData($paymentData);
    }
}


<?php

namespace PlentyConnector\Components\Klarna\Plentymarkets;

use PlentyConnector\Components\Klarna\PaymentData\KlarnaPaymentData;
use PlentymarketsAdapter\RequestGenerator\Payment\PaymentRequestGeneratorInterface;
use SystemConnector\TransferObject\Payment\Payment;

class KlarnaRequestGenerator implements PaymentRequestGeneratorInterface
{
    /**
     * @var PaymentRequestGeneratorInterface
     */
    private $parentRequestGenerator;

    public function __construct(PaymentRequestGeneratorInterface $parentRequestGenerator)
    {
        $this->parentRequestGenerator = $parentRequestGenerator;
    }

    /**
     * {@inheritdoc}
     */
    public function generate(Payment $payment)
    {
        $paymentParams = $this->parentRequestGenerator->generate($payment);
        $data = $payment->getPaymentData();

        if (!($data instanceof KlarnaPaymentData)) {
            return $paymentParams;
        }

        $paymentParams['properties'][] = [
            'typeId' => 2,
            'value' => $data->getTransactionId() . '_' . $data->getPclassId() . '_' . $data->getShopId(),
        ];

        return $paymentParams;
    }
}


<?php

namespace ShopwareAdapter\ServiceBus\CommandHandler\Manufacturer;

use Shopware\Components\Api\Exception\NotFoundException as ManufacturerNotFoundException;
use Shopware\Components\Api\Resource\Manufacturer as ManufacturerResource;
use ShopwareAdapter\DataPersister\Attribute\AttributeDataPersisterInterface;
use ShopwareAdapter\ShopwareAdapter;
use SystemConnector\IdentityService\IdentityServiceInterface;
use SystemConnector\ServiceBus\Command\CommandInterface;
use SystemConnector\ServiceBus\Command\TransferObjectCommand;
use SystemConnector\ServiceBus\CommandHandler\CommandHandlerInterface;
use SystemConnector\ServiceBus\CommandType;
use SystemConnector\TransferObject\Manufacturer\Manufacturer;
use SystemConnector\TransferObject\Media\Media;

class HandleManufacturerCommandHandler implements CommandHandlerInterface
{
    /**
     * @var ManufacturerResource
     */
    private $resource;

    /**
     * @var IdentityServiceInterface
     */
    private $identityService;

    /**
     * @var AttributeDataPersisterInterface
     */
    private $attributePersister;

    public function __construct(
        ManufacturerResource $resource,
        IdentityServiceInterface $identityService,
        AttributeDataPersisterInterface $attributePersister
    ) {
        $this->resource = $resource;
        $this->identityService = $identityService;
        $this->attributePersister = $attributePersister;
    }

    /**
     * {@inheritdoc}
     */
    public function supports(CommandInterface $command)
    {
        return $command instanceof TransferObjectCommand &&
            $command->getAdapterName() === ShopwareAdapter::NAME &&
            $command->getObjectType() === Manufacturer::TYPE &&
            $command->getCommandType() === CommandType::HANDLE;
    }

    /**
     * {@inheritdoc}
     *
     * @param TransferObjectCommand $command
     */
    public function handle(CommandInterface $command)
    {
        /**
         * @var Manufacturer $manufacturer
         */
        $manufacturer = $command->getPayload();

        $params = [
            'name' => $manufacturer->getName(),
        ];

        if (null !== $manufacturer->getLink()) {
            $params['link'] = $manufacturer->getLink();
        }

        if (null !== $manufacturer->getLogoIdentifier()) {
            $mediaIdentity = $this->identityService->findOneBy([
                'objectIdentifier' => (string) $manufacturer->getLogoIdentifier(),
                'objectType' => Media::TYPE,
                'adapterName' => ShopwareAdapter::NAME,
            ]);

            if (null !== $mediaIdentity) {
                $params['image'] = [
                    'mediaId' => $mediaIdentity->getAdapterIdentifier(),
                ];
            }
        }

        $identity = $this->identityService->findOneBy([
            'objectIdentifier' => (string) $manufacturer->getIdentifier(),
            'objectType' => Manufacturer::TYPE,
            'adapterName' => ShopwareAdapter::NAME,
        ]);

        if (null === $identity) {
            $existingManufacturer = $this->findExistingManufacturer($manufacturer);

            if (null !== $existingManufacturer) {
                $identity = $this->identityService->insert(
                    (string) $manufacturer->getIdentifier(),
                    Manufacturer::TYPE,
                    (string) $existingManufacturer['id'],
                    ShopwareAdapter::NAME
                );
            }
        }

        if ($identity) {
            try {
                $this->resource->getOne($identity->getAdapterIdentifier());
            } catch (ManufacturerNotFoundException $exception) {
                $this->identityService->remove($identity);

                $identity = null;
            }
        }

        if (null === $identity) {
            $manufacturerModel = $this->resource->create($params);

            $this->identityService->insert(
                (string) $manufacturer->getIdentifier(),
                Manufacturer::TYPE,
                (string) $manufacturerModel->getId(),
                ShopwareAdapter::NAME
            );
        } else {
            $manufacturerModel = $this->resource->update($identity->getAdapterIdentifier(), $params);
        }

        $this->attributePersister->saveManufacturerAttributes(
            $manufacturerModel,
            $manufacturer->getAttributes()
        );

        return true;
    }

    /**
     * @param Manufacturer $manufacturer
     *
     * @return null|array
     */
    private function findExistingManufacturer(Manufacturer $manufacturer)
    {
        $result = $this->resource->getList(0, 1, [
            'supplier.name' => $manufacturer->getName(),
        ]);

        if (0 === count($result['data'])) {
            return null;
        }

        return array_shift($result['data']);
    }
}


<?php

namespace PlentyConnector\Components\Bundle\TransferObject;

use DateTimeImmutable;
use PlentyConnector\Components\Bundle\TransferObject\BundleProduct\BundleProduct;
use SystemConnector\TransferObject\AbstractTransferObject;
use SystemConnector\TransferObject\Product\Price\Price;
use SystemConnector\ValueObject\Attribute\Attribute;
use SystemConnector\ValueObject\Translation\Translation;

class Bundle extends AbstractTransferObject
{
    const TYPE = 'Bundle';

    /**
     * @var string
     */
    private $identifier = '';

    /**
     * @var bool
     */
    private $active = false;

    /**
     * @var string
     */
    private $productIdentifier = '';

    /**
     * @var string
     */
    private $name;

    /**
     * @var string
     */
    private $number;

    /**
     * @var int
     */
    private $position = 0;

    /**
     * @var float
     */
    private $stock = 0;

    /**
     * @var bool
     */
    private $stockLimitation = false;

    /**
     * @var Price[]
     */
    private $prices = [];

    /**
     * @var string
     */
    private $vatRateIdentifier = '';

    /**
     * @var null|DateTimeImmutable
     */
    private $availableFrom;

    /**
     * @var null|DateTimeImmutable
     */
    private $availableTo;

    /**
     * @var BundleProduct[]
     */
    private $bundleProducts = [];

    /**
     * @var Attribute[]
     */
    private $attributes = [];

    /**
     * @var Translation[]
     */
    private $translations = [];

    /**
     * {@inheritdoc}
     */
    public function getType()
    {
        return self::TYPE;
    }

    /**
     * @return string
     */
    public function getIdentifier()
    {
        return $this->identifier;
    }

    /**
     * @param string $identifier
     */
    public function setIdentifier($identifier)
    {
        $this->identifier = $identifier;
    }

    /**
     * @return bool
     */
    public function isActive()
    {
        return $this->active;
    }

    /**
     * @param bool $active
     */
    public function setActive($active)
    {
        $this->active = $active;
    }

    /**
     * @return string
     */
    public function getProductIdentifier()
    {
        return $this->productIdentifier;
    }

    /**
     * @param string $productIdentifier
     */
    public function setProductIdentifier($productIdentifier)
    {
        $this->productIdentifier = $productIdentifier;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param string $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @return string
     */
    public function getNumber()
    {
        return $this->number;
    }

    /**
     * @param string $number
     */
    public function setNumber($number)
    {
        $this->number = $number;
    }

    /**
     * @return int
     */
    public function getPosition()
    {
        return $this->position;
    }

    /**
     * @param int $position
     */
    public function setPosition($position)
    {
        $this->position = $position;
    }

    /**
     * @return float
     */
    public function getStock()
    {
        return $this->stock;
    }

    /**
     * @param float $stock
     */
    public function setStock($stock)
    {
        $this->stock = $stock;
    }

    /**
     * @return bool
     */
    public function hasStockLimitation()
    {
        return $this->stockLimitation;
    }

    /**
     * @param bool $stockLimitation
     */
    public function setStockLimitation($stockLimitation)
    {
        $this->stockLimitation = $stockLimitation;
    }

    /**
     * @return Price[]
     */
    public function getPrices()
    {
        return $this->prices;
    }

    /**
     * @param Price[] $prices
     */
    public function setPrices($prices)
    {
        $this->prices = $prices;
    }

    /**
     * @return string
     */
    public function getVatRateIdentifier()
    {
        return $this->vatRateIdentifier;
    }

    /**
     * @param string $vatRateIdentifier
     */
    public function setVatRateIdentifier($vatRateIdentifier)
    {
        $this->vatRateIdentifier = $vatRateIdentifier;
    }

    /**
     * @return null|DateTimeImmutable
     */
    public function getAvailableFrom()
    {
        return $this->availableFrom;
    }

    /**
     * @param null|DateTimeImmutable $availableFrom
     */
    public function setAvailableFrom(DateTimeImmutable $availableFrom = null)
    {
        $this->availableFrom = $availableFrom;
    }

    /**
     * @return null|DateTimeImmutable
     */
    public function getAvailableTo()
    {
        return $this->availableTo;
    }

    /**
     * @param null|DateTimeImmutable $availableTo
     */
    public function setAvailableTo(DateTimeImmutable $availableTo = null)
    {
        $this->availableTo = $availableTo;
    }

    /**
     * @return BundleProduct[]
     */
    public function getBundleProducts()
    {
        return $this->bundleProducts;
    }

    /**
     * @param BundleProduct[] $bundleProducts
     */
    public function setBundleProducts($bundleProducts)
    {
        $this->bundleProducts = $bundleProducts;
    }

    /**
     * @return Attribute[]
     */
    public function getAttributes()
    {
        return $this->attributes;
    }

    /**
     * @param Attribute[] $attributes
     */
    public function setAttributes($attributes)
    {
        $this->attributes = $attributes;
    }

    /**
     * @return Translation[]
     */
    public function getTranslations()
    {
        return $this->translations;
    }

    /**
     * @param Translation[] $translations
     */
    public function setTranslations(array $translations)
    {
        $this->translations = $translations;
    }

    /**
     * {@inheritdoc}
     */
    public function getClassProperties()
    {
        return [
            'identifier' => $this->getIdentifier(),
            'active' => $this->isActive(),
            'productIdentifier' => $this->getProductIdentifier(),
            'name' => $this->getName(),
            'number' => $this->getNumber(),
            'position' => $this->getPosition(),
            'stock' => $this->getStock(),
            'stockLimitation' => $this->hasStockLimitation(),
            'prices' => $this->getPrices(),
            'vatRateIdentifier' => $this->getVatRateIdentifier(),
            'availableFrom' => $this->getAvailableFrom(),
            'availableTo' => $this->getAvailableTo(),
            'bundleProducts' => $this->getBundleProducts(),
            'attributes' => $this->getAttributes(),
            'translations' => $this->getTranslations(),
        ];
    }
}


<?php

namespace PlentyConnector\Components\Sepa\Shopware;

use Assert\Assertion;
use Doctrine\ORM\EntityRepository;
use InvalidArgumentException;
use PlentyConnector\Components\Sepa\PaymentData\SepaPaymentData;
use Shopware\Models\Shop\Currency as CurrencyModel;
use ShopwareAdapter\ResponseParser\Payment\PaymentResponseParserInterface;
use ShopwareAdapter\ShopwareAdapter;
use SystemConnector\IdentityService\IdentityServiceInterface;
use SystemConnector\TransferObject\Currency\Currency;
use SystemConnector\TransferObject\Order\Order;
use SystemConnector\TransferObject\Payment\Payment;
use SystemConnector\TransferObject\PaymentMethod\PaymentMethod;
use SystemConnector\TransferObject\Shop\Shop;

class SepaPaymentResponseParser implements PaymentResponseParserInterface
{
    /**
     * @var PaymentResponseParserInterface
     */
    private $parentResponseParser;

    /**
     * @var IdentityServiceInterface
     */
    private $identityService;

    public function __construct(
        PaymentResponseParserInterface $parentResponseParser,
        IdentityServiceInterface $identityService
    ) {
        $this->parentResponseParser = $parentResponseParser;
        $this->identityService = $identityService;
    }

    /**
     * {@inheritdoc}
     */
    public function parse(array $element)
    {
        $payments = $this->parentResponseParser->parse($element);

        if (!$this->hasSepaPaymentInstance($element)) {
            return $payments;
        }

        if (empty($payments)) {
            $identifier = $this->getIdentifier($element['id'], Payment::TYPE);

            $payment = new Payment();
            $payment->setOrderIdentifer($this->getIdentifier($element['id'], Order::TYPE));
            $payment->setIdentifier($identifier);
            $payment->setShopIdentifier($this->getIdentifier($element['shopId'], Shop::TYPE));
            $payment->setTransactionReference($identifier);
            $payment->setCurrencyIdentifier($this->getIdentifier($this->getCurrencyId($element['currency']), Currency::TYPE));
            $payment->setPaymentMethodIdentifier($this->getIdentifier($element['paymentId'], PaymentMethod::TYPE));

            $payments = [$payment];
        }

        foreach ($payments as $payment) {
            if (!($payment instanceof Payment)) {
                continue;
            }

            $payment->setPaymentData($this->getSepaPaymentData($element));
        }

        return $payments;
    }

    /**
     * @param int    $entry
     * @param string $type
     *
     * @return string
     */
    private function getIdentifier($entry, $type)
    {
        Assertion::integerish($entry);

        return $this->identityService->findOneOrThrow(
            (string) $entry,
            ShopwareAdapter::NAME,
            $type
        )->getObjectIdentifier();
    }

    /**
     * @param string $currency
     *
     * @return int
     */
    private function getCurrencyId($currency)
    {
        /**
         * @var EntityRepository $currencyRepository
         */
        $currencyRepository = Shopware()->Models()->getRepository(CurrencyModel::class);

        /**
         * @var null|CurrencyModel $model
         */
        $model = $currencyRepository->findOneBy(['currency' => $currency]);

        if (null === $model) {
            throw new InvalidArgumentException('could not find currency model by currency: ' . $currency);
        }

        return $model->getId();
    }

    /**
     * @param array $element
     *
     * @return SepaPaymentData
     */
    private function getSepaPaymentData(array $element)
    {
        $paymentInstance = array_shift($element['paymentInstances']);

        $sepaPaymentData = new SepaPaymentData();
        $sepaPaymentData->setAccountOwner($paymentInstance['accountHolder']);
        $sepaPaymentData->setIban($paymentInstance['iban']);
        $sepaPaymentData->setBic($paymentInstance['bic']);

        return $sepaPaymentData;
    }

    /**
     * @param array $element
     *
     * @return bool
     */
    private function hasSepaPaymentInstance(array $element)
    {
        if (empty($element['paymentInstances'])) {
            return false;
        }

        $paymentInstance = array_shift($element['paymentInstances']);

        if (empty($paymentInstance['iban'])) {
            return false;
        }

        if (empty($paymentInstance['bic'])) {
            return false;
        }

        return true;
    }
}


<?php

namespace SystemConnector\ConfigService\Storage;

use DateTimeInterface;
use Doctrine\DBAL\Connection;

class DatabaseConfigServiceStorage implements ConfigServiceStorageInterface
{
    /**
     * @var string
     */
    private $table;

    /**
     * @var Connection
     */
    private $connection;

    /**
     * @param Connection $connection
     * @param string     $table
     */
    public function __construct(Connection $connection, $table)
    {
        $this->connection = $connection;
        $this->table = $table;
    }

    /**
     * {@inheritdoc}
     */
    public function getAll()
    {
        $queryBuilder = $this->connection->createQueryBuilder();
        $queryBuilder->from($this->table, 'config');
        $queryBuilder->select([
            'config.name',
            'config.value',
        ]);

        $configElements = $queryBuilder->execute()->fetchAll();

        $result = [];

        foreach ($configElements as $element) {
            $result[$element['name']] = $element['value'];
        }

        return $result;
    }

    /**
     * {@inheritdoc}
     */
    public function get($name)
    {
        $queryBuilder = $this->connection->createQueryBuilder();
        $queryBuilder->from($this->table, 'config');
        $queryBuilder->select([
            'config.value',
        ]);
        $queryBuilder->andWhere('config.name = :name');
        $queryBuilder->setParameter(':name', $name);

        $configValue = $queryBuilder->execute()->fetchColumn();

        if (!$configValue) {
            return null;
        }

        return $configValue;
    }

    /**
     * {@inheritdoc}
     */
    public function set($name, $value)
    {
        $queryBuilder = $this->connection->createQueryBuilder();
        $queryBuilder->from($this->table, 'config')
            ->select(['config.name'])
            ->where('config.name = :name')
            ->setParameter(':name', $name);
        $configElement = $queryBuilder->execute()->fetchColumn();

        if ($value instanceof DateTimeInterface) {
            $value = $value->format(DATE_W3C);
        }

        if (!empty($configElement)) {
            $this->connection->update(
                $this->table,
                [
                    'value' => $value,
                ],
                [
                    'name' => $name,
                ]
            );
        } else {
            $this->connection->insert($this->table, [
                'name' => $name,
                'value' => $value,
            ]);
        }
    }
}


<?php

namespace PlentyConnector\Components\Sepa\Plentymarkets;

use PlentyConnector\Components\Sepa\PaymentData\SepaPaymentData;
use PlentymarketsAdapter\Client\ClientInterface;
use PlentymarketsAdapter\PlentymarketsAdapter;
use SystemConnector\IdentityService\Exception\NotFoundException;
use SystemConnector\IdentityService\IdentityServiceInterface;
use SystemConnector\IdentityService\Struct\Identity;
use SystemConnector\ServiceBus\Command\CommandInterface;
use SystemConnector\ServiceBus\Command\TransferObjectCommand;
use SystemConnector\ServiceBus\CommandHandler\CommandHandlerInterface;
use SystemConnector\ServiceBus\CommandType;
use SystemConnector\TransferObject\Order\Order;
use SystemConnector\TransferObject\Payment\Payment;

class HandleSepaPaymentCommandHandler implements CommandHandlerInterface
{
    /**
     * @var CommandHandlerInterface
     */
    private $parentCommandHandler;

    /**
     * @var ClientInterface
     */
    private $client;

    /**
     * @var IdentityServiceInterface
     */
    private $identityService;

    public function __construct(
        CommandHandlerInterface $parentCommandHandler,
        ClientInterface $client,
        IdentityServiceInterface $identityService
    ) {
        $this->parentCommandHandler = $parentCommandHandler;
        $this->client = $client;
        $this->identityService = $identityService;
    }

    /**
     * {@inheritdoc}
     */
    public function supports(CommandInterface $command)
    {
        return $command instanceof TransferObjectCommand &&
            $command->getAdapterName() === PlentymarketsAdapter::NAME &&
            $command->getObjectType() === Payment::TYPE &&
            $command->getCommandType() === CommandType::HANDLE;
    }

    /**
     * {@inheritdoc}
     *
     * @var TransferObjectCommand $command
     */
    public function handle(CommandInterface $command)
    {
        /**
         * @var Payment $payment
         */
        $payment = $command->getPayload();

        /**
         * @var SepaPaymentData $data
         */
        $data = $payment->getPaymentData();

        if (!($data instanceof SepaPaymentData)) {
            return $this->parentCommandHandler->handle($command);
        }

        $identity = $this->identityService->findOneBy([
            'objectIdentifier' => $payment->getIdentifier(),
            'objectType' => Payment::TYPE,
            'adapterName' => PlentymarketsAdapter::NAME,
        ]);

        if (null !== $identity) {
            return true;
        }

        $orderIdentity = $this->identityService->findOneBy([
            'objectIdentifier' => $payment->getOrderIdentifer(),
            'objectType' => Order::TYPE,
            'adapterName' => PlentymarketsAdapter::NAME,
        ]);

        if (null === $orderIdentity) {
            throw new NotFoundException('could not find order for bank account handling - ' . $payment->getOrderIdentifer());
        }

        $contactId = $this->getContactIdentifier($orderIdentity);

        if (null === $contactId) {
            throw new NotFoundException('could not find contact for bank account handling - ' . $payment->getOrderIdentifer());
        }

        $bankAccounts = $this->client->request('GET', 'accounts/contacts/' . $contactId . '/banks');

        $possibleBankAccounts = array_filter($bankAccounts, function (array $bankAccount) use ($data, $orderIdentity) {
            return $bankAccount['iban'] === $data->getIban() && $bankAccount['orderId'] === (int) $orderIdentity->getAdapterIdentifier();
        });

        if (!empty($possibleBankAccounts)) {
            $possibleBankAccounts = array_shift($possibleBankAccounts);

            $this->identityService->insert(
                $payment->getIdentifier(),
                Payment::TYPE,
                (string) $possibleBankAccounts['id'],
                PlentymarketsAdapter::NAME
            );

            return true;
        }

        $sepaPaymentDataParams = [
            'lastUpdateBy' => 'import',
            'accountOwner' => $data->getAccountOwner(),
            'iban' => $data->getIban(),
            'bic' => $data->getBic(),
            'orderId' => $orderIdentity->getAdapterIdentifier(),
            'contactId' => $contactId,
        ];

        $paymentResult = $this->client->request('POST', 'accounts/contacts/banks', $sepaPaymentDataParams);

        $this->identityService->insert(
            $payment->getIdentifier(),
            Payment::TYPE,
            (string) $paymentResult['id'],
            PlentymarketsAdapter::NAME
        );

        return true;
    }

    /**
     * @param Identity $orderIdentity
     *
     * @return null|int
     */
    private function getContactIdentifier(Identity $orderIdentity)
    {
        $order = $this->client->request('GET', 'orders/' . $orderIdentity->getAdapterIdentifier());

        $relations = array_filter($order['relations'], function (array $relation) {
            return $relation['referenceType'] === 'contact';
        });

        if (empty($relations)) {
            return null;
        }

        $contactRelation = array_shift($relations);

        return $contactRelation['referenceId'];
    }
}


<?php

namespace SystemConnector\TransferObject\Media;

use SystemConnector\TransferObject\AbstractTransferObject;
use SystemConnector\TransferObject\AttributableInterface;
use SystemConnector\TransferObject\TranslateableInterface;
use SystemConnector\ValueObject\Attribute\Attribute;
use SystemConnector\ValueObject\Translation\Translation;

class Media extends AbstractTransferObject implements TranslateableInterface, AttributableInterface
{
    const TYPE = 'Media';

    /**
     * @var string
     */
    private $identifier = '';

    /**
     * @var string
     */
    private $mediaCategoryIdentifier = '';

    /**
     * link to the actual media
     *
     * @var string
     */
    private $link;

    /**
     * @var string
     */
    private $filename;

    /**
     * @var string
     */
    private $hash = '';

    /**
     * @var null|string
     */
    private $name;

    /**
     * @var null|string
     */
    private $alternateName;

    /**
     * @var Translation[]
     */
    private $translations = [];

    /**
     * @var Attribute[]
     */
    private $attributes = [];

    /**
     * {@inheritdoc}
     */
    public function getType()
    {
        return self::TYPE;
    }

    /**
     * {@inheritdoc}
     */
    public function getIdentifier()
    {
        return $this->identifier;
    }

    /**
     * {@inheritdoc}
     */
    public function setIdentifier($identifier)
    {
        $this->identifier = $identifier;
    }

    /**
     * @return string
     */
    public function getMediaCategoryIdentifier()
    {
        return $this->mediaCategoryIdentifier;
    }

    /**
     * @param string $mediaCategoryIdentifier
     */
    public function setMediaCategoryIdentifier($mediaCategoryIdentifier)
    {
        $this->mediaCategoryIdentifier = $mediaCategoryIdentifier;
    }

    /**
     * @return string
     */
    public function getLink()
    {
        return $this->link;
    }

    /**
     * @param string $link
     */
    public function setLink($link)
    {
        $this->link = $link;
    }

    /**
     * @return string
     */
    public function getFilename()
    {
        return $this->filename;
    }

    /**
     * @param string $filename
     */
    public function setFilename($filename)
    {
        $this->filename = $filename;
    }

    /**
     * @return string
     */
    public function getHash()
    {
        return $this->hash;
    }

    /**
     * @param null|string $hash
     */
    public function setHash($hash = null)
    {
        $this->hash = $hash;
    }

    /**
     * @return null|string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param null|string $name
     */
    public function setName($name = null)
    {
        $this->name = $name;
    }

    /**
     * @return null|string
     */
    public function getAlternateName()
    {
        return $this->alternateName;
    }

    /**
     * @param null|string $alternateName
     */
    public function setAlternateName($alternateName = null)
    {
        $this->alternateName = $alternateName;
    }

    /**
     * @return Translation[]
     */
    public function getTranslations()
    {
        return $this->translations;
    }

    /**
     * @param Translation[] $translations
     */
    public function setTranslations(array $translations)
    {
        $this->translations = $translations;
    }

    /**
     * @return Attribute[]
     */
    public function getAttributes()
    {
        return $this->attributes;
    }

    /**
     * @param Attribute[] $attributes
     */
    public function setAttributes(array $attributes)
    {
        $this->attributes = $attributes;
    }

    /**
     * {@inheritdoc}
     */
    public function getClassProperties()
    {
        return [
            'identifier' => $this->getIdentifier(),
            'mediaCategoryIdentifier' => $this->getMediaCategoryIdentifier(),
            'link' => $this->getLink(),
            'filename' => $this->getFilename(),
            'hash' => $this->getHash(),
            'name' => $this->getName(),
            'alternateName' => $this->getAlternateName(),
            'translations' => $this->getTranslations(),
            'attributes' => $this->getAttributes(),
        ];
    }
}


<?php

namespace PlentymarketsAdapter\ResponseParser\Media;

use Assert\Assertion;
use PlentymarketsAdapter\Helper\MediaCategoryHelper;
use PlentymarketsAdapter\PlentymarketsAdapter;
use SystemConnector\IdentityService\IdentityServiceInterface;
use SystemConnector\TransferObject\Media\Media;
use SystemConnector\TransferObject\MediaCategory\MediaCategory;

class MediaResponseParser implements MediaResponseParserInterface
{
    /**
     * @var IdentityServiceInterface
     */
    private $identityService;

    /**
     * @var MediaCategoryHelper
     */
    private $categoryHelper;

    public function __construct(
        IdentityServiceInterface $identityService,
        MediaCategoryHelper $categoryHelper
    ) {
        $this->identityService = $identityService;
        $this->categoryHelper = $categoryHelper;
    }

    /**
     * {@inheritdoc}
     */
    public function parse(array $entry)
    {
        Assertion::url($entry['link']);

        if (empty($entry['filename'])) {
            $entry['filename'] = basename($entry['link']);
        }

        if (empty($entry['name'])) {
            $entry['name'] = null;
        }

        if (empty($entry['alternateName'])) {
            $entry['alternateName'] = null;
        }

        if (!array_key_exists('translations', $entry)) {
            $entry['translations'] = [];
        }

        if (!array_key_exists('attributes', $entry)) {
            $entry['attributes'] = [];
        }

        if (array_key_exists('mediaCategory', $entry)) {
            $mediaCategories = $this->categoryHelper->getCategories();

            $mediaCategoryIdentity = $this->identityService->findOneOrCreate(
                (string) $mediaCategories[$entry['mediaCategory']]['id'],
                PlentymarketsAdapter::NAME,
                MediaCategory::TYPE
            );

            $entry['mediaCategoryIdentifier'] = $mediaCategoryIdentity->getObjectIdentifier();
        } else {
            $entry['mediaCategoryIdentifier'] = null;
        }

        $entry['hash'] = sha1(json_encode($entry)); // include all fields when computing the hash

        $identity = $this->identityService->findOneOrCreate(
            (string) $entry['id'],
            PlentymarketsAdapter::NAME,
            Media::TYPE
        );

        $media = new Media();
        $media->setIdentifier($identity->getObjectIdentifier());
        $media->setMediaCategoryIdentifier($entry['mediaCategoryIdentifier']);
        $media->setLink($entry['link']);
        $media->setFilename($entry['filename']);
        $media->setHash($entry['hash']);
        $media->setName($entry['name']);
        $media->setAlternateName($entry['alternateName']);
        $media->setTranslations($entry['translations']);
        $media->setAttributes($entry['attributes']);

        return $media;
    }
}


<?php

namespace PlentymarketsAdapter\ResponseParser\Product\Price;

use PlentymarketsAdapter\PlentymarketsAdapter;
use PlentymarketsAdapter\ReadApi\Account\ContactClass;
use PlentymarketsAdapter\ReadApi\Item\SalesPrice;
use Psr\Log\LoggerInterface;
use SystemConnector\ConfigService\ConfigServiceInterface;
use SystemConnector\IdentityService\IdentityServiceInterface;
use SystemConnector\IdentityService\Struct\Identity;
use SystemConnector\TransferObject\CustomerGroup\CustomerGroup;
use SystemConnector\TransferObject\Product\Price\Price;
use SystemConnector\TransferObject\Shop\Shop;

class PriceResponseParser implements PriceResponseParserInterface
{
    /**
     * @var IdentityServiceInterface
     */
    private $identityService;

    /**
     * @var SalesPrice
     */
    private $itemsSalesPricesApi;

    /**
     * @var ContactClass
     */
    private $itemsAccountsContacsClasses;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var ConfigServiceInterface
     */
    private $configService;

    public function __construct(
        IdentityServiceInterface $identityService,
        SalesPrice $itemsSalesPricesApi,
        ContactClass $itemsAccountsContacsClasses,
        LoggerInterface $logger,
        ConfigServiceInterface $configService
    ) {
        $this->identityService = $identityService;
        $this->itemsSalesPricesApi = $itemsSalesPricesApi;
        $this->itemsAccountsContacsClasses = $itemsAccountsContacsClasses;
        $this->logger = $logger;
        $this->configService = $configService;
    }

    /**
     * @param array $variation
     *
     * @return Price[]
     */
    public function parse(array $variation)
    {
        $temporaryPrices = $this->getPricesAsSortedArray($variation['variationSalesPrices']);

        /**
         * @var Price[] $prices
         */
        $prices = [];
        foreach ($temporaryPrices as $customerGroup => $priceArray) {
            if (!isset($priceArray['default'])) {
                continue;
            }

            if ($customerGroup === 'default') {
                $customerGroup = null;
            }

            foreach ((array) $priceArray['default'] as $salesPrice) {
                $priceObject = new Price();
                $priceObject->setPrice($salesPrice['price']);
                $priceObject->setCustomerGroupIdentifier($customerGroup);
                $priceObject->setFromAmount($salesPrice['from']);

                $this->addPseudoPrice($priceObject, $priceArray);

                $prices[] = $priceObject;
            }
        }

        foreach ($prices as $price) {
            /**
             * @var Price[] $possibleScalePrices
             */
            $possibleScalePrices = array_filter($prices, function (Price $possiblePrice) use ($price) {
                return $possiblePrice->getCustomerGroupIdentifier() === $price->getCustomerGroupIdentifier() &&
                    spl_object_hash($price) !== spl_object_hash($possiblePrice);
            });

            if (empty($possibleScalePrices)) {
                continue;
            }

            usort($possibleScalePrices, function (Price $possibleScalePriceLeft, Price $possibleScalePriceright) {
                if ($possibleScalePriceLeft->getFromAmount() === $possibleScalePriceright->getFromAmount()) {
                    return 0;
                }

                if ($possibleScalePriceLeft->getFromAmount() > $possibleScalePriceright->getFromAmount()) {
                    return 1;
                }

                return -1;
            });

            foreach ($possibleScalePrices as $possibleScalePrice) {
                if ($possibleScalePrice->getFromAmount() > $price->getFromAmount()) {
                    $price->setToAmount($possibleScalePrice->getFromAmount() - 1);

                    break;
                }
            }
        }

        return $prices;
    }

    /**
     * @param string $orderOrigin
     * @param array  $referrers
     *
     * @return bool
     */
    private function checkIfOriginIsInReferrers($orderOrigin, array $referrers)
    {
        foreach ($referrers as $referrer) {
            if ($referrer['referrerId'] === $orderOrigin) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param array $variationSalesPrices
     *
     * @return array
     */
    private function getPricesAsSortedArray(array $variationSalesPrices = [])
    {
        $priceConfigurations = $this->getPriceConfigurations();

        if (empty($priceConfigurations)) {
            $this->logger->notice('no valid price configuration found');

            return [];
        }

        static $customerGroups;

        if (null === $customerGroups) {
            $customerGroups = array_keys($this->itemsAccountsContacsClasses->findAll());
        }

        $temporaryPrices = [];

        foreach ($variationSalesPrices as $price) {
            $priceConfiguration = $this->filterPriceConfiguration($priceConfigurations, $price);

            if (empty($priceConfiguration)) {
                // no price configuration found, skip price

                continue;
            }

            $priceConfiguration = array_shift($priceConfiguration);
            $customerClasses = (array) $priceConfiguration['customerClasses'];
            $from = (float) $priceConfiguration['minimumOrderQuantity'];

            if (count($customerClasses) === 1 && $customerClasses[0]['customerClassId'] === -1) {
                foreach ($customerGroups as $group) {
                    $customerGroupIdentity = $this->identityService->findOneBy([
                        'adapterIdentifier' => $group,
                        'adapterName' => PlentymarketsAdapter::NAME,
                        'objectType' => CustomerGroup::TYPE,
                    ]);

                    if (null === $customerGroupIdentity) {
                        continue;
                    }

                    $customerGroup = $customerGroupIdentity->getObjectIdentifier();

                    $temporaryPrices[$customerGroup][$priceConfiguration['type']][$from] = [
                        'from' => $from,
                        'price' => (float) $price['price'],
                    ];
                }
            } else {
                foreach ($customerClasses as $group) {
                    $customerGroupIdentity = $this->identityService->findOneBy([
                        'adapterIdentifier' => $group['customerClassId'],
                        'adapterName' => PlentymarketsAdapter::NAME,
                        'objectType' => CustomerGroup::TYPE,
                    ]);

                    if (null === $customerGroupIdentity) {
                        continue;
                    }

                    $customerGroup = $customerGroupIdentity->getObjectIdentifier();

                    $temporaryPrices[$customerGroup][$priceConfiguration['type']][$from] = [
                        'from' => $from,
                        'price' => (float) $price['price'],
                    ];
                }
            }
        }

        return $temporaryPrices;
    }

    /**
     * Returns the matching price configurations.
     *
     * @return array
     */
    private function getPriceConfigurations()
    {
        static $priceConfigurations;

        if (null === $priceConfigurations) {
            $priceConfigurations = $this->itemsSalesPricesApi->findAll();

            $shopIdentities = $this->identityService->findBy([
                'adapterName' => PlentymarketsAdapter::NAME,
                'objectType' => Shop::TYPE,
            ]);

            $shopIdentities = array_filter($shopIdentities, function (Identity $identity) {
                $isMappedIdentity = $this->identityService->isMappedIdentity(
                    $identity->getObjectIdentifier(),
                    $identity->getObjectType(),
                    $identity->getAdapterName()
                );

                if (!$isMappedIdentity) {
                    return false;
                }

                return true;
            });

            if (empty($shopIdentities)) {
                $priceConfigurations = [];

                return $priceConfigurations;
            }

            $priceConfigurations = array_filter($priceConfigurations,
                function ($priceConfiguration) use ($shopIdentities) {
                    foreach ($shopIdentities as $identity) {
                        foreach ((array) $priceConfiguration['clients'] as $client) {
                            if ($client['plentyId'] === -1 || $identity->getAdapterIdentifier() === (string) $client['plentyId']) {
                                return true;
                            }
                        }
                    }

                    return false;
                });

            if (empty($priceConfigurations)) {
                $this->logger->notice('no valid price configuration found');
            }
        }

        return $priceConfigurations;
    }

    /**
     * @param Price $price
     * @param array $priceArray
     */
    private function addPseudoPrice(Price $price, $priceArray)
    {
        if (isset($priceArray['rrp'][$price->getFromAmount()])) {
            $pseudoPrice = $priceArray['rrp'][$price->getFromAmount()]['price'];

            if ($pseudoPrice > $price->getPrice()) {
                $price->setPseudoPrice($pseudoPrice);
            }
        }

        if (isset($priceArray['specialOffer'][$price->getFromAmount()])) {
            $specialPrice = $priceArray['specialOffer'][$price->getFromAmount()]['price'];

            if (0.0 === $price->getPseudoPrice() && $specialPrice < $price->getPrice()) {
                $price->setPseudoPrice($price->getPrice());
            }

            $price->setPrice($priceArray['specialOffer'][$price->getFromAmount()]['price']);
        }
    }

    /**
     * @param array $priceConfigurations
     * @param array $price
     *
     * @return array
     */
    private function filterPriceConfiguration($priceConfigurations, $price)
    {
        $orderOrigin = (int) $this->configService->get('order_origin');

        $priceConfiguration = array_filter($priceConfigurations, function ($configuration) use ($price) {
            return $configuration['id'] === $price['salesPriceId'];
        });

        if ('true' === $this->configService->get('check_price_origin')) {
            $priceConfiguration = array_filter($priceConfiguration, function ($configuration) use ($price, $orderOrigin) {
                if ($this->checkIfOriginIsInReferrers($orderOrigin, (array) $configuration['referrers'])) {
                    return $configuration['id'] === $price['salesPriceId'];
                }

                return false;
            });
        }

        return $priceConfiguration;
    }
}