1
0
Fork 0
mirror of synced 2025-04-20 01:21:01 +00:00

more models, api corporate customer builder & bitrix customer builder

This commit is contained in:
Pavel 2020-07-30 15:03:49 +03:00
parent 77aac323e2
commit f33d86812f
28 changed files with 1493 additions and 74 deletions

View file

@ -3,7 +3,7 @@ class RetailCrmService
{
public static function unsetIntegrationDeliveryFields($order)
{
$integrationDelivery = unserialize(COption::GetOptionString(RetailcrmConstants::MODULE_ID, RetailcrmConstants::CRM_INTEGRATION_DELIVERY, 0));
$integrationDelivery = RetailcrmConfigProvider::getIntegrationDeliveriesMapping();
$deliveryCode = $order['delivery']['code'];
if ($deliveryCode) {
switch ($integrationDelivery[$deliveryCode]) {

View file

@ -11,21 +11,154 @@
*/
namespace Intaro\RetailCrm\Component\Builder\Api;
use Bitrix\Main\Type\DateTime;
use Bitrix\Sale\Order;
use Intaro\RetailCrm\Component\Builder\BuilderInterface;
use Intaro\RetailCrm\Component\Builder\Exception\BuilderException;
use Intaro\RetailCrm\Component\CollectorCookieExtractor;
use Intaro\RetailCrm\Component\ConfigProvider;
use Intaro\RetailCrm\Component\Converter\DateTimeConverter;
use Intaro\RetailCrm\Component\Events;
use Intaro\RetailCrm\Model\Api\Address;
use Intaro\RetailCrm\Model\Api\Company;
use Intaro\RetailCrm\Model\Api\Contragent;
use Intaro\RetailCrm\Model\Api\Customer;
use Intaro\RetailCrm\Model\Api\CustomerContact;
use Intaro\RetailCrm\Model\Bitrix\User;
use Intaro\RetailCrm\Repository\UserRepository;
/**
* Class CorporateCustomerBuilder
*
*TODO
* Support for building corporate customers is partial for now. Full support should be implemented, which would be
* possible with a full refactoring. For current purposes this will work.
*
* @package Intaro\RetailCrm\Component\Builder\Api
*/
class CorporateCustomerBuilder implements BuilderInterface
{
/** @var \Intaro\RetailCrm\Model\Bitrix\User $user */
private $user;
/** @var \Intaro\RetailCrm\Model\Api\Customer $customer */
private $customer;
/** @var \Bitrix\Sale\Order $order */
private $order;
/** @var array */
private $sites;
/** @var array */
private $legalDetails;
/** @var array */
private $contragentTypes;
/** @var string */
private $foundAddress;
/** @var bool */
private $buildChildEntities = false;
/** @var bool */
private $mainCompany = false;
/** @var bool */
private $mainContact = false;
/** @var bool */
private $mainAddress = false;
/** @var bool */
private $attachDaemonCollectorId = false;
/**
* @inheritDoc
* CorporateCustomerBuilder constructor.
*/
public function __construct()
{
$this->sites = ConfigProvider::getSitesList();
$this->legalDetails = ConfigProvider::getLegalDetails();
$this->contragentTypes = ConfigProvider::getContragentTypes();
}
/**
* @return $this|\Intaro\RetailCrm\Component\Builder\BuilderInterface
* @throws \Bitrix\Main\ArgumentException
* @throws \Bitrix\Main\NotImplementedException
* @throws \Bitrix\Main\ObjectPropertyException
* @throws \Bitrix\Main\SystemException
* @throws \Intaro\RetailCrm\Component\Builder\Exception\BuilderException
*/
public function build(): BuilderInterface
{
// TODO: Implement build() method.
if (!($this->order instanceof Order)) {
throw new BuilderException('Order should be provided for building corporate customer!');
}
$contragentType = ConfigProvider::getContragentTypeForPersonType($this->order->getPersonTypeId());
if (null === $contragentType) {
throw new BuilderException(sprintf(
'Cannot find corresponding contragent type for PERSON_TYPE_ID `%s`',
$this->order->getPersonTypeId()
));
}
$this->customer = new Customer();
$dateCreated = $this->order->getDateInsert();
if ($dateCreated instanceof DateTime) {
$this->customer->createdAt = DateTimeConverter::bitrixToPhp($dateCreated);
}
$this->buildLegalDetails();
if ($this->buildChildEntities) {
$this->buildCustomerContact();
$this->buildCustomerCompany();
$this->buildCustomerAddresses();
}
if ($this->attachDaemonCollectorId) {
$this->buildDaemonCollectorId();
}
return $this;
}
/**
* @param bool $buildChildEntities
*
* @return CorporateCustomerBuilder
*/
public function setBuildChildEntities(bool $buildChildEntities): CorporateCustomerBuilder
{
$this->buildChildEntities = $buildChildEntities;
return $this;
}
/**
* @param bool $mainCompany
*
* @return CorporateCustomerBuilder
*/
public function setMainCompany(bool $mainCompany): CorporateCustomerBuilder
{
$this->mainCompany = $mainCompany;
return $this;
}
/**
* @param bool $mainContact
*
* @return CorporateCustomerBuilder
*/
public function setMainContact(bool $mainContact): CorporateCustomerBuilder
{
$this->mainContact = $mainContact;
return $this;
}
@ -34,7 +167,16 @@ class CorporateCustomerBuilder implements BuilderInterface
*/
public function reset(): BuilderInterface
{
// TODO: Implement reset() method.
$this->user = null;
$this->customer = null;
$this->order = null;
$this->foundAddress = null;
$this->buildChildEntities = false;
$this->mainAddress = false;
$this->mainCompany = false;
$this->mainContact = false;
$this->attachDaemonCollectorId = false;
return $this;
}
@ -43,6 +185,152 @@ class CorporateCustomerBuilder implements BuilderInterface
*/
public function getResult()
{
// TODO: Implement getResult() method.
Events::push(Events::API_CORPORATE_CUSTOMER_BUILDER_GET_RESULT, ['customer' => $this->customer]);
return $this->customer;
}
/**
* @param \Intaro\RetailCrm\Model\Bitrix\User $user
*
* @return CorporateCustomerBuilder
*/
public function setUser(User $user): CorporateCustomerBuilder
{
$this->user = $user;
return $this;
}
/**
* @param \Bitrix\Sale\Order $order
*
* @return CorporateCustomerBuilder
* @throws \Bitrix\Main\ArgumentException
* @throws \Bitrix\Main\ObjectPropertyException
* @throws \Bitrix\Main\SystemException
*/
public function setOrder(Order $order): CorporateCustomerBuilder
{
$this->order = $order;
$this->user = UserRepository::getById($order->getUserId());
return $this;
}
/**
* @param bool $attachDaemonCollectorId
*
* @return CorporateCustomerBuilder
*/
public function setAttachDaemonCollectorId(bool $attachDaemonCollectorId): CorporateCustomerBuilder
{
$this->attachDaemonCollectorId = $attachDaemonCollectorId;
return $this;
}
/**
* @throws \Bitrix\Main\ArgumentException
* @throws \Bitrix\Main\NotImplementedException
* @throws \Bitrix\Main\ObjectPropertyException
* @throws \Bitrix\Main\SystemException
*/
protected function buildLegalDetails(): void
{
$this->customer->contragent = new Contragent();
/** @var \Bitrix\Sale\PropertyValue $property */
foreach ($this->order->getPropertyCollection() as $property) {
if (ConfigProvider::getCorporateClientName() === $property->getField('CODE')) {
$this->customer->nickName = $property->getValue();
}
if (ConfigProvider::getCorporateClientAddress() === $property->getField('CODE')) {
$this->foundAddress = $property->getValue();
}
if (!empty($this->legalDetails)) {
$contragentProperty = array_search(
$property->getField('CODE'),
$this->legalDetails[$this->order->getPersonTypeId()],
false
);
if (property_exists(Contragent::class, $contragentProperty)) {
$this->customer->contragent->$contragentProperty = $property->getValue();
}
}
}
if (array_key_exists($this->order->getPersonTypeId(), $this->contragentTypes)) {
$this->customer->contragent->contragentType = $this->contragentTypes[$this->order->getPersonTypeId()];
}
if (empty($this->customer->nickName)) {
$this->customer->nickName = $this->user->getWorkCompany();
}
}
/**
* @throws \Intaro\RetailCrm\Component\Builder\Exception\BuilderException
*/
protected function buildCustomerContact(): void
{
$site = null;
$shop = $this->order->getField('LID');
if (array_key_exists($shop, $this->sites) && !empty($this->sites[$shop])) {
$site = $this->sites[$shop];
}
if (null === $site) {
throw new BuilderException(sprintf(
'Site `%s` is not connected to any sites in the retailCRM',
$shop
));
}
$contact = new CustomerContact();
$contact->isMain = $this->mainContact;
$contact->customer = new Customer();
$contact->customer->externalId = $this->user->getId();
$contact->customer->site = $site;
$this->customer->customerContacts = [$contact];
}
/**
* Builds customer company
*/
protected function buildCustomerCompany(): void
{
$company = new Company();
$company->name = $this->customer->nickName;
$company->isMain = $this->mainCompany;
$this->customer->companies = [$company];
}
/**
* Builds customer addresses
*/
protected function buildCustomerAddresses(): void
{
if (!empty($this->foundAddress)) {
$address = new Address();
$address->name = $this->customer->nickName;
$address->text = $this->foundAddress;
$address->isMain = $this->mainAddress;
$this->customer->addresses = [$address];
}
}
/**
* Integrated Daemon Collector cookie (if it's present).
*/
protected function buildDaemonCollectorId(): void
{
if (CollectorCookieExtractor::extractCookie()) {
$this->customer->browserId = CollectorCookieExtractor::extractCookie();
}
}
}

View file

@ -39,6 +39,9 @@ class CustomerBuilder implements BuilderInterface
/** @var string $personTypeId */
private $personTypeId;
/** @var bool */
private $attachDaemonCollectorId = false;
/**
* @inheritDoc
*/
@ -57,8 +60,66 @@ class CustomerBuilder implements BuilderInterface
$this->buildNames();
$this->buildPhones();
$this->buildAddress();
$this->buildDaemonCollectorId();
if ($this->attachDaemonCollectorId) {
$this->buildDaemonCollectorId();
}
return $this;
}
/**
* @inheritDoc
*/
public function reset(): BuilderInterface
{
$this->user = null;
$this->customer = null;
$this->personTypeId = null;
return $this;
}
/**
* @inheritDoc
*/
public function getResult()
{
Events::push(Events::API_CUSTOMER_BUILDER_GET_RESULT, ['customer' => $this->customer]);
return $this->customer;
}
/**
* @param \Intaro\RetailCrm\Model\Bitrix\User $user
*
* @return CustomerBuilder
*/
public function setUser(User $user): CustomerBuilder
{
$this->user = $user;
return $this;
}
/**
* @param string $personTypeId
*
* @return CustomerBuilder
*/
public function setPersonTypeId(string $personTypeId): CustomerBuilder
{
$this->personTypeId = $personTypeId;
return $this;
}
/**
* @param bool $attachDaemonCollectorId
*
* @return CustomerBuilder
*/
public function setAttachDaemonCollectorId(bool $attachDaemonCollectorId): CustomerBuilder
{
$this->attachDaemonCollectorId = $attachDaemonCollectorId;
return $this;
}
@ -146,45 +207,4 @@ class CustomerBuilder implements BuilderInterface
$phone->number = $number;
$this->customer->phones[] = $phone;
}
/**
* @inheritDoc
*/
public function reset(): BuilderInterface
{
$this->user = null;
$this->customer = null;
}
/**
* @inheritDoc
*/
public function getResult()
{
Events::push(Events::CUSTOMER_BUILDER_GET_RESULT, ['customer' => $this->customer]);
return $this->customer;
}
/**
* @param \Intaro\RetailCrm\Model\Bitrix\User $user
*
* @return CustomerBuilder
*/
public function setUser(User $user): CustomerBuilder
{
$this->user = $user;
return $this;
}
/**
* @param string $personTypeId
*
* @return CustomerBuilder
*/
public function setPersonTypeId(string $personTypeId): CustomerBuilder
{
$this->personTypeId = $personTypeId;
return $this;
}
}

View file

@ -0,0 +1,223 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Component\Builder
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Component\Builder;
use Intaro\RetailCrm\Component\Converter\DateTimeConverter;
use Intaro\RetailCrm\Component\Events;
use Intaro\RetailCrm\Component\Utils;
use Intaro\RetailCrm\Model\Api\Customer;
use Intaro\RetailCrm\Model\Bitrix\User;
/**
* Class CustomerBuilder
*
* @package Intaro\RetailCrm\Component\Builder
*/
class CustomerBuilder implements BuilderInterface
{
/** @var \Intaro\RetailCrm\Model\Bitrix\User */
protected $user;
/** @var \Intaro\RetailCrm\Model\Api\Customer */
protected $customer;
/**
* @param \Intaro\RetailCrm\Model\Bitrix\User $user
*
* @return $this
*/
public function setUser($user): self
{
$this->user = $user;
return $this;
}
/**
* @return \Intaro\RetailCrm\Model\Bitrix\User
*/
public function getUser(): User
{
return $this->user;
}
/**
* @param \Intaro\RetailCrm\Model\Api\Customer $customer
*
* @return CustomerBuilder
*/
public function setCustomer(Customer $customer): CustomerBuilder
{
$this->customer = $customer;
return $this;
}
public function build(): BuilderInterface
{
if (null === $this->user) {
$this->user = new User();
}
$this->buildNames();
$this->buildPhones();
$this->buildAddress();
$this->buildBirthdaySexAndEmail();
$this->fillFieldsForHistoryClient();
return $this;
}
/**
* @param string $login
* @return $this
*/
public function setLogin($login): self
{
$this->user->setLogin($login);
return $this;
}
/**
* @param string $email
* @return $this
*/
public function setEmail($email): self
{
$this->user->setEmail($email);
return $this;
}
/**
* @inheritDoc
*/
public function reset(): BuilderInterface
{
$this->customer = null;
$this->user = null;
return $this;
}
/**
* @inheritDoc
*/
public function getResult()
{
Events::push(Events::BITRIX_CUSTOMER_BUILDER_GET_RESULT, ['customer' => $this->user]);
return $this->user;
}
/**
* Fill first name, last name and second name in the user
*/
protected function buildNames(): void
{
if (!empty($this->customer->firstName)) {
$this->user->setName(Utils::fromUTF8($this->customer->firstName));
}
if (!empty($this->customer->lastName)) {
$this->user->setLastName(Utils::fromUTF8($this->customer->lastName));
}
if (!empty($this->customer->patronymic)) {
$this->user->setSecondName(Utils::fromUTF8($this->customer->patronymic));
}
}
/**
* Fill phone numbers in the user
*/
protected function buildPhones(): void
{
if (!empty($this->customer->phones)) {
foreach ($this->customer->phones as $phone) {
if (!empty($phone->oldNumber)) {
if ($this->user->getPersonalPhone() == $phone->oldNumber) {
$this->user->setPersonalPhone($phone->number);
}
if ($this->user->getWorkPhone() == $phone->oldNumber) {
$this->user->setWorkPhone($phone->number);
}
}
if (isset($phone['number'])) {
if (strlen($this->user->getPersonalPhone()) == 0
&& $this->user->getPersonalPhone() != $phone->number
) {
$this->user->setPersonalPhone($phone->number);
continue;
}
if (strlen($this->user->getPersonalMobile()) == 0
&& $this->user->getPersonalMobile() != $phone->number
) {
$this->user->setPersonalMobile($phone['number']);
continue;
}
}
}
}
}
/**
* Fill zip code and city in the user
*/
protected function buildAddress(): void
{
if (!empty($this->customer->address)) {
if (!empty($this->customer->address->index)) {
$this->user->setPersonalZip(Utils::fromUTF8($this->customer->address->index));
}
if (!empty($this->customer->address->city)) {
$this->user->setPersonalCity(Utils::fromUTF8($this->customer->address->city));
}
}
}
/**
* Fill birthday, email and gender in the user
*/
protected function buildBirthdaySexAndEmail(): void
{
if (!empty($this->customer->birthday)) {
$this->user->setPersonalBirthday(DateTimeConverter::phpToBitrix($this->customer->birthday));
}
if (!empty($this->customer->email)) {
$this->user->setEmail(Utils::fromUTF8($this->customer->email));
}
if (!empty($this->customer->sex)) {
$this->user->setPersonalGender(Utils::fromUTF8($this->customer->sex));
}
}
/**
* Fill fields with placeholders in the user (only for new users from history, when some data is not provided).
*/
protected function fillFieldsForHistoryClient(): void
{
if (empty($this->customer->externalId)) {
$this->user->setPassword(Utils::createPlaceholderPassword());
}
if (empty($this->customer->email) && empty($this->customer->externalId)) {
$login = Utils::createPlaceholderEmail();
$this->user->setLogin($login);
$this->user->setEmail($login);
}
}
}

View file

@ -97,6 +97,9 @@ class ConfigProvider
/** @var array $shops */
protected static $shops;
/** @var array $integrationDeliveriesMapping */
protected static $integrationDeliveriesMapping;
/**
* @return bool|string|null
*/
@ -163,6 +166,16 @@ class ConfigProvider
return static::$corporateClient;
}
/**
* Returns true if corporate clients are enabled
*
* @return bool
*/
public static function isCorporateClientEnabled(): bool
{
return self::getCorporateClientStatus() === 'Y';
}
/**
* getSitesList
*
@ -558,6 +571,21 @@ class ConfigProvider
return static::getExternalOption("main", "new_user_phone_required") === 'Y';
}
/**
* Returns integration delivery mapping
*
* @return array
*/
public static function getIntegrationDeliveriesMapping(): array
{
if (empty(self::$integrationDeliveriesMapping)) {
self::$integrationDeliveriesMapping =
(array) static::getUnserializedOption(Constants::CRM_INTEGRATION_DELIVERY);
}
return self::$integrationDeliveriesMapping;
}
/**
* Wraps Bitrix \COption::GetOptionString(...)
*

View file

@ -68,4 +68,5 @@ class Constants
public const CANCEL_PROPERTY_CODE = 'INTAROCRM_IS_CANCELED';
public const CRM_INTEGRATION_DELIVERY = 'integration_delivery';
public const CRM_SHIPMENT_DEDUCTED = 'shipment_deducted';
public const CORPORATE_CONTRAGENT_TYPE = 'legal-entity';
}

View file

@ -20,7 +20,20 @@ use Bitrix\Main\Event;
*/
class Events
{
public const CUSTOMER_BUILDER_GET_RESULT = 'OnRetailcrmApiCustomerBuilderGetResult';
/**
* Fired before returning result from retailCRM customer builder (customer for retailCRM API)
*/
public const API_CUSTOMER_BUILDER_GET_RESULT = 'OnRetailcrmApiCustomerBuilderGetResult';
/**
* Fired before returning result from retailCRM corporate customer builder (customer for retailCRM API)
*/
public const API_CORPORATE_CUSTOMER_BUILDER_GET_RESULT = 'OnRetailcrmApiCorporateCustomerBuilderGetResult';
/**
* Fired before returning result from retailCRM customer builder (builds user data for Bitrix)
*/
public const BITRIX_CUSTOMER_BUILDER_GET_RESULT = 'OnRetailcrmBitrixCustomerBuilderGetResult';
/**
* Push event

View file

@ -11,7 +11,6 @@
*/
namespace Intaro\RetailCrm\Component\Json\Strategy\Deserialize;
use Intaro\RetailCrm\Component\Doctrine\Common\Annotations\AnnotationReader;
use Intaro\RetailCrm\Component\Json\Mapping\Accessor;
use Intaro\RetailCrm\Component\Json\Mapping\SerializedName;
use Intaro\RetailCrm\Component\Json\Mapping\Type;
@ -68,23 +67,22 @@ class EntityStrategy implements DeserializeStrategyInterface
*/
protected static function deserializeProperty($object, \ReflectionProperty $property, array $data): void
{
$type = '';
$name = $property->getName();
$accessorData = static::annotationReader()->getPropertyAnnotation($property, Accessor::class);
$nameData = static::annotationReader()->getPropertyAnnotation($property, SerializedName::class);
$typeData = static::annotationReader()->getPropertyAnnotation($property, Type::class);
if ($nameData instanceof SerializedName) {
$name = !empty($nameData->name) ? $nameData->name : $name;
if (!($nameData instanceof SerializedName)) {
return;
}
$accessorData = static::annotationReader()->getPropertyAnnotation($property, Accessor::class);
$typeData = static::annotationReader()->getPropertyAnnotation($property, Type::class);
if ($typeData instanceof Type) {
$type = $typeData->type;
} else {
$type = gettype($data[$name]);
$type = gettype($data[$nameData->name]);
}
$value = StrategyFactory::deserializeStrategyByType($type)->deserialize($type, $data[$name]);
$value = StrategyFactory::deserializeStrategyByType($type)->deserialize($type, $data[$nameData->name]);
if ($accessorData instanceof Accessor && !empty($accessorData->setter)) {
$object->{$accessorData->setter}($value);

View file

@ -59,8 +59,13 @@ class EntityStrategy implements SerializeStrategyInterface
*/
protected static function serializeProperty($object, \ReflectionProperty $property, array &$result): void
{
$nameData = static::annotationReader()->getPropertyAnnotation($property, SerializedName::class);
if (!($nameData instanceof SerializedName)) {
return;
}
$accessorData = static::annotationReader()->getPropertyAnnotation($property, Accessor::class);
$name = $property->getName();
if ($accessorData instanceof Accessor && !empty($accessorData->getter)) {
$value = $object->{$accessorData->getter}();
@ -69,17 +74,12 @@ class EntityStrategy implements SerializeStrategyInterface
$value = $property->getValue($object);
}
$nameData = static::annotationReader()->getPropertyAnnotation($property, SerializedName::class);
$typeData = static::annotationReader()->getPropertyAnnotation($property, Type::class);
if ($nameData instanceof SerializedName) {
$name = !empty($nameData->name) ? $nameData->name : $name;
}
if ($typeData instanceof Type) {
$result[$name] = StrategyFactory::serializeStrategyByType($typeData->type)->serialize($value);
$result[$nameData->name] = StrategyFactory::serializeStrategyByType($typeData->type)->serialize($value);
} else {
$result[$name] = StrategyFactory::serializeStrategyByType(gettype($value))->serialize($value);
$result[$nameData->name] = StrategyFactory::serializeStrategyByType(gettype($value))->serialize($value);
}
}
}

View file

@ -12,6 +12,7 @@
namespace Intaro\RetailCrm\Component;
use Bitrix\Main\Text\Encoding;
use Intaro\RetailCrm\Model\Api\Order\Order;
/**
* Class Utils
@ -75,6 +76,34 @@ class Utils
return static::convertCharset($string, 'utf-8', SITE_CHARSET);
}
/**
* Returns true if provided PERSON_TYPE_ID is corporate customer
*
* @param string $personTypeId
*
* @return bool
*/
public static function isPersonCorporate(string $personTypeId): bool
{
return ConfigProvider::getContragentTypeForPersonType($personTypeId) === Constants::CORPORATE_CONTRAGENT_TYPE;
}
/**
* @return string
*/
public static function createPlaceholderEmail(): string
{
return uniqid('user_' . time(), false) . '@example.com';
}
/**
* @return string
*/
public static function createPlaceholderPassword(): string
{
return uniqid("R", false);
}
/**
* @param string $string
* @param string $inCharset

View file

@ -20,7 +20,7 @@ use Intaro\RetailCrm\Component\Utils;
*
* @package Intaro\RetailCrm\Model\Api
*/
class AbstractApiModel implements ApiModelInterface
class AbstractApiModel implements ApiModelInterface, \Traversable
{
/**
* @PostDeserialize()

View file

@ -190,4 +190,20 @@ class Address extends AbstractApiModel
* @Mapping\SerializedName("text")
*/
public $text;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("country")
*/
public $country;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("intercomCode")
*/
public $intercomCode;
}

View file

@ -0,0 +1,39 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Model\Api
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Model\Api;
use Intaro\RetailCrm\Component\Json\Mapping;
/**
* Class CodeValueModel
*
* @package Intaro\RetailCrm\Model\Api
*/
class CodeValueModel extends AbstractApiModel
{
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("code")
*/
public $code;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("value")
*/
public $value;
}

View file

@ -160,6 +160,26 @@ class Customer extends AbstractApiModel
*/
public $phones;
/**
* Дата рождения
*
* @var \DateTime
*
* @Mapping\Type("DateTime<'Y-m-d'>")
* @Mapping\SerializedName("birthday")
*/
public $birthday;
/**
* Пол
*
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("sex")
*/
public $sex;
/**
* ID менеджера, к которому привязан клиент
*

View file

@ -3,20 +3,20 @@
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Model\Api
* @package Intaro\RetailCrm\Model\Api\Order
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Model\Api;
namespace Intaro\RetailCrm\Model\Api\Order;
use Intaro\RetailCrm\Component\Json\Mapping;
/**
* Class Order
*
* @package Intaro\RetailCrm\Model\Api
* @package Intaro\RetailCrm\Model\Api\Order
*/
class Order extends AbstractApiModel
{
@ -30,6 +30,16 @@ class Order extends AbstractApiModel
*/
public $id;
/**
* Номер заказа
*
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("number")
*/
public $number;
/**
* Внешний ID корпоративного клиента
*
@ -69,4 +79,45 @@ class Order extends AbstractApiModel
* @Mapping\SerializedName("status")
*/
public $status;
/**
* @var \Intaro\RetailCrm\Model\Api\Order\SerializedOrderDelivery
*
*
* @Mapping\Type("Intaro\RetailCrm\Model\Api\Order\SerializedOrderDelivery")
* @Mapping\SerializedName("delivery")
*/
public $delivery;
/**
* @var double
*
* @Mapping\Type("double")
* @Mapping\SerializedName("weight")
*/
public $weight;
/**
* @var int
*
* @Mapping\Type("int")
* @Mapping\SerializedName("length")
*/
public $length;
/**
* @var int
*
* @Mapping\Type("int")
* @Mapping\SerializedName("width")
*/
public $width;
/**
* @var int
*
* @Mapping\Type("int")
* @Mapping\SerializedName("height")
*/
public $height;
}

View file

@ -0,0 +1,70 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Model\Api\Order
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Model\Api\Order;
use Intaro\RetailCrm\Component\Json\Mapping;
/**
* Class OrderDeliveryData
*
* @package Intaro\RetailCrm\Model\Api\Order
*/
class OrderDeliveryData extends AbstractApiModel
{
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("externalId")
*/
public $externalId;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("trackNumber")
*/
public $trackNumber;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("tariff")
*/
public $tariff;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("pickuppointId")
*/
public $pickuppointId;
/**
* @var array
*
* @Mapping\Type("array")
* @Mapping\SerializedName("extraData")
*/
public $extraData;
/**
* @var \Intaro\RetailCrm\Model\Api\Order\Package[]
*
* @Mapping\Type("Intaro\RetailCrm\Model\Api\Order\Package[]")
* @Mapping\SerializedName("packages")
*/
public $packages;
}

View file

@ -0,0 +1,70 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Model\Api\Order
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Model\Api\Order;
use Intaro\RetailCrm\Component\Json\Mapping;
/**
* Class Package
*
* @package Intaro\RetailCrm\Model\Api\Order
*/
class Package extends AbstractApiModel
{
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("packageId")
*/
public $packageId;
/**
* @var double
*
* @Mapping\Type("double")
* @Mapping\SerializedName("weight")
*/
public $weight;
/**
* @var int
*
* @Mapping\Type("int")
* @Mapping\SerializedName("length")
*/
public $length;
/**
* @var int
*
* @Mapping\Type("int")
* @Mapping\SerializedName("width")
*/
public $width;
/**
* @var int
*
* @Mapping\Type("int")
* @Mapping\SerializedName("height")
*/
public $height;
/**
* @var \Intaro\RetailCrm\Model\Api\Order\PackageItem[]
*
* @Mapping\Type("Intaro\RetailCrm\Model\Api\Order\PackageItem[]")
* @Mapping\SerializedName("items")
*/
public $items;
}

View file

@ -0,0 +1,38 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Model\Api\Order
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Model\Api\Order;
use Intaro\RetailCrm\Component\Json\Mapping;
/**
* Class PackageItem
*
* @package Intaro\RetailCrm\Model\Api\Order
*/
class PackageItem extends AbstractApiModel
{
/**
* @var \Intaro\RetailCrm\Model\Api\Order\PackageItemOrderProduct
*
* @Mapping\Type("Intaro\RetailCrm\Model\Api\Order\PackageItemOrderProduct")
* @Mapping\SerializedName("orderProduct")
*/
public $orderProduct;
/**
* @var double
*
* @Mapping\Type("double")
* @Mapping\SerializedName("quantity")
*/
public $quantity;
}

View file

@ -0,0 +1,46 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Model\Api\Order
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Model\Api\Order;
use Intaro\RetailCrm\Component\Json\Mapping;
/**
* Class PackageItemOrderProduct
*
* @package Intaro\RetailCrm\Model\Api\Order
*/
class PackageItemOrderProduct extends AbstractApiModel
{
/**
* @var int
*
* @Mapping\Type("int")
* @Mapping\SerializedName("id")
*/
public $id;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("externalId")
*/
public $externalId;
/**
* @var \Intaro\RetailCrm\Model\Api\CodeValueModel
*
* @Mapping\Type("Intaro\RetailCrm\Model\Api\CodeValueModel")
* @Mapping\SerializedName("externalIds")
*/
public $externalIds;
}

View file

@ -0,0 +1,54 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Model\Api\Order
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Model\Api\Order;
use Intaro\RetailCrm\Component\Json\Mapping;
/**
* Class SerializedDeliveryService
*
* @package Intaro\RetailCrm\Model\Api\Order
*/
class SerializedDeliveryService extends AbstractApiModel
{
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("name")
*/
public $name;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("code")
*/
public $code;
/**
* @var bool
*
* @Mapping\Type("bool")
* @Mapping\SerializedName("active")
*/
public $active;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("deliveryType")
*/
public $deliveryType;
}

View file

@ -0,0 +1,81 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Model\Api\Order
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Model\Api\Order;
use Intaro\RetailCrm\Component\Json\Mapping;
/**
* Class SerializedOrderDelivery
*
* @package Intaro\RetailCrm\Model\Api\Order
*/
class SerializedOrderDelivery extends AbstractApiModel
{
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("code")
*/
public $code;
/**
* @var \Intaro\RetailCrm\Model\Api\Order\OrderDeliveryData
*
* @Mapping\Type("Intaro\RetailCrm\Model\Api\Order\OrderDeliveryData")
* @Mapping\SerializedName("data")
*/
public $data;
/**
* @var \Intaro\RetailCrm\Model\Api\Order\SerializedDeliveryService
*
* @Mapping\Type("Intaro\RetailCrm\Model\Api\Order\SerializedDeliveryService")
* @Mapping\SerializedName("service")
*/
public $service;
/**
* @var double
*
* @Mapping\Type("double")
* @Mapping\SerializedName("cost")
*/
public $cost;
/**
* @var double
*
* @Mapping\Type("double")
* @Mapping\SerializedName("netCost")
*/
public $netCost;
/**
* @var \DateTime
*
* @Mapping\Type("DateTime<'Y-m-d H:i:s'>")
* @Mapping\SerializedName("date")
*/
public $date;
/**
* @var \Intaro\RetailCrm\Model\Api\TimeInterval
*
* @Mapping\Type("Intaro\RetailCrm\Model\Api\TimeInterval")
* @Mapping\SerializedName("time")
*/
public $time;
//TODO:
// order[delivery][address] model
}

View file

@ -29,4 +29,11 @@ class Phone extends AbstractApiModel
* @Mapping\SerializedName("number")
*/
public $number;
/**
* Старый номер телефона. Используется только в истории, игнорируется при сериализации.
*
* @var string $oldNumber
*/
public $oldNumber;
}

View file

@ -0,0 +1,47 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Model\Api
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Model\Api;
use Intaro\RetailCrm\Component\Json\Mapping;
/**
* Class TimeInterval
*
* @package Intaro\RetailCrm\Model\Api
*/
class TimeInterval extends AbstractApiModel
{
/**
* @var \DateTime
*
* @Mapping\Type("DateTime<'Y-m-d H:i:s'>")
* @Mapping\SerializedName("from")
*/
public $from;
/**
* @var \DateTime
*
* @Mapping\Type("DateTime<'Y-m-d H:i:s'>")
* @Mapping\SerializedName("to")
*/
public $to;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("to")
*/
public $custom;
}

View file

@ -0,0 +1,103 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Model\Bitrix
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Model\Bitrix;
use Intaro\RetailCrm\Component\Json\Mapping;
/**
* Class BuyerProfile
*
* @package Intaro\RetailCrm\Model\Bitrix
*/
class BuyerProfile
{
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("NAME")
*/
protected $name;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("USER_ID")
*/
protected $userId;
/**
* @var string
*
* @Mapping\Type("string")
* @Mapping\SerializedName("PERSON_TYPE_ID")
*/
protected $personTypeId;
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @param string $name
*
* @return BuyerProfile
*/
public function setName(string $name): BuyerProfile
{
$this->name = $name;
return $this;
}
/**
* @return string
*/
public function getUserId(): string
{
return $this->userId;
}
/**
* @param string $userId
*
* @return BuyerProfile
*/
public function setUserId(string $userId): BuyerProfile
{
$this->userId = $userId;
return $this;
}
/**
* @return string
*/
public function getPersonTypeId(): string
{
return $this->personTypeId;
}
/**
* @param string $personTypeId
*
* @return BuyerProfile
*/
public function setPersonTypeId(string $personTypeId): BuyerProfile
{
$this->personTypeId = $personTypeId;
return $this;
}
}

View file

@ -0,0 +1,83 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Model\Api
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Repository;
use Bitrix\Sale\OrderUserProperties;
use Intaro\RetailCrm\Component\Json\Deserializer;
use Intaro\RetailCrm\Component\Json\Serializer;
use Intaro\RetailCrm\Model\Bitrix\BuyerProfile;
/**
* Class UserRepository
*
* @package Intaro\RetailCrm\Repository
*/
class BuyerProfileRepository extends AbstractRepository
{
/**
* Returns true if provided BuyerProfile exists
*
* @param \Intaro\RetailCrm\Model\Bitrix\BuyerProfile $buyerProfile
*
* @return bool
*/
public static function isProfileExists(BuyerProfile $buyerProfile): bool
{
$profileData = Serializer::serializeArray($buyerProfile);
$found = static::findProfileByData($profileData);
return !empty($found);
}
/**
* @param \Intaro\RetailCrm\Model\Bitrix\BuyerProfile $buyerProfile
*
* @return \Intaro\RetailCrm\Model\Bitrix\BuyerProfile|null
*/
public static function add(BuyerProfile $buyerProfile): ?BuyerProfile
{
$profileData = Serializer::serializeArray($buyerProfile);
$buyerProfileInstance = new \CSaleOrderUserProps();
if ($buyerProfileInstance->Add($profileData)) {
$profileData = OrderUserProperties::getList(array(
"filter" => $buyerProfile
))->fetch();
}
return static::deserialize($profileData);
}
/**
* Returns array with buyer profile if one was found. Returns empty array otherwise.
*
* @param array $profileData
*
* @return array
*/
private static function findProfileByData(array $profileData): array
{
return OrderUserProperties::getList(array(
"filter" => $profileData
))->fetch();
}
/**
* @param array $buyerProfileData
*
* @return \Intaro\RetailCrm\Model\Bitrix\BuyerProfile
*/
private static function deserialize(array $buyerProfileData): BuyerProfile
{
return Deserializer::deserializeArray($buyerProfileData, BuyerProfile::class);
}
}

53
tests/helpers/Helpers.php Normal file
View file

@ -0,0 +1,53 @@
<?php
namespace Tests\Intaro\RetailCrm;
use Intaro\RetailCrm\Component\ConfigProvider;
class Helpers
{
/** @var \ReflectionClass */
private static $configReflection;
/**
* Sets property into config provider
*
* @param string $propertyName
* @param mixed $value
*
* @throws \ReflectionException
*/
public static function setConfigProperty(string $propertyName, $value)
{
static::regenerateConfigReflection();
$property = static::$configReflection->getProperty($propertyName);
$property->setAccessible(true);
$property->setValue($value);
}
/**
* Sets property into config provider
*
* @param string $propertyName
*
* @return mixed
* @throws \ReflectionException
*/
public static function getConfigProperty(string $propertyName): mixed
{
static::regenerateConfigReflection();
$property = static::$configReflection->getProperty($propertyName);
$property->setAccessible(true);
return $property->getValue();
}
/**
* Regenerates config reflection
*/
protected static function regenerateConfigReflection(): void
{
if (null === static::$configReflection) {
static::$configReflection = new \ReflectionClass(ConfigProvider::class);
}
}
}

View file

@ -0,0 +1,43 @@
<?php
namespace Tests\Intaro\RetailCrm\Component\Builder\Api;
use Bitrix\Sale\Order;
use Intaro\RetailCrm\Component\Builder\Api\CorporateCustomerBuilder;
use Intaro\RetailCrm\Component\Builder\Exception\BuilderException;
use PHPUnit\Framework\TestCase;
use Tests\Intaro\RetailCrm\Helpers;
class CorporateCustomerBuilderTest extends TestCase
{
protected function setUp(): void
{
Helpers::setConfigProperty('sitesList', ['s1' => 's1']);
Helpers::setConfigProperty('corporateClientName', 'COMPANY');
Helpers::setConfigProperty('corporateClientAddress', 'COMPANY_ADR');
Helpers::setConfigProperty('contragentTypes', [
'individual',
'legal-entity'
]);
Helpers::setConfigProperty('legalDetails', [
'individual',
'legal-entity'
]);
}
public function testBuildNoOrder(): void
{
$this->expectException(BuilderException::class);
(new CorporateCustomerBuilder())->build();
}
public function testNoCorrespondingContragentType()
{
$this->expectException(BuilderException::class);
$order = Order::create('s1');
$order->setField('LID', 'unknown_site');
(new CorporateCustomerBuilder())
->setOrder($order)
->build();
}
}

View file

@ -15,15 +15,13 @@ use Intaro\RetailCrm\Model\Api\Customer;
use Intaro\RetailCrm\Model\Bitrix\User;
use PHPUnit\Framework\Constraint\IsType;
use PHPUnit\Framework\TestCase;
use Tests\Intaro\RetailCrm\Helpers;
class CustomerBuilderTest extends TestCase
{
protected function setUp(): void
{
$class = new \ReflectionClass(ConfigProvider::class);
$property = $class->getProperty('contragentTypes');
$property->setAccessible(true);
$property->setValue([
Helpers::setConfigProperty('contragentTypes', [
'individual' => 'individual'
]);
}
@ -77,7 +75,7 @@ class CustomerBuilderTest extends TestCase
EventManager::getInstance()->addEventHandler(
Constants::MODULE_ID,
Events::CUSTOMER_BUILDER_GET_RESULT,
Events::API_CUSTOMER_BUILDER_GET_RESULT,
static function (Event $event) {
$event->getParameter('customer')->externalId = 'replaced';
}