From 7892aab91aefe0da4383b13b41eb8a1323b24829 Mon Sep 17 00:00:00 2001 From: Vadim Soluyanov Date: Wed, 18 Jun 2025 16:21:22 +0400 Subject: [PATCH 1/8] add class Quote with its methods --- .../Events/OnCrmQuoteAdd/OnCrmQuoteAdd.php | 26 ++ .../OnCrmQuoteAdd/OnCrmQuoteAddPayload.php | 26 ++ .../OnCrmQuoteDelete/OnCrmQuoteDelete.php | 26 ++ .../OnCrmQuoteDeletePayload.php | 25 ++ .../OnCrmQuoteUpdate/OnCrmQuoteUpdate.php | 26 ++ .../OnCrmQuoteUpdatePayload.php | 26 ++ .../CRM/Quote/Result/QuoteItemResult.php | 98 ++++++ src/Services/CRM/Quote/Result/QuoteResult.php | 33 ++ .../Quote/Result/QuoteUserfieldItemResult.php | 21 ++ .../CRM/Quote/Result/QuoteUserfieldResult.php | 28 ++ .../Quote/Result/QuoteUserfieldsResult.php | 35 ++ .../CRM/Quote/Result/QuotesResult.php | 40 +++ src/Services/CRM/Quote/Service/Batch.php | 249 ++++++++++++++ src/Services/CRM/Quote/Service/Quote.php | 324 ++++++++++++++++++ .../CRM/Quote/Service/QuoteUserfield.php | 236 +++++++++++++ 15 files changed, 1219 insertions(+) create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAdd.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAddPayload.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDelete.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDeletePayload.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdate.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdatePayload.php create mode 100644 src/Services/CRM/Quote/Result/QuoteItemResult.php create mode 100644 src/Services/CRM/Quote/Result/QuoteResult.php create mode 100644 src/Services/CRM/Quote/Result/QuoteUserfieldItemResult.php create mode 100644 src/Services/CRM/Quote/Result/QuoteUserfieldResult.php create mode 100644 src/Services/CRM/Quote/Result/QuoteUserfieldsResult.php create mode 100644 src/Services/CRM/Quote/Result/QuotesResult.php create mode 100644 src/Services/CRM/Quote/Service/Batch.php create mode 100644 src/Services/CRM/Quote/Service/Quote.php create mode 100644 src/Services/CRM/Quote/Service/QuoteUserfield.php diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAdd.php b/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAdd.php new file mode 100644 index 00000000..32d6cca6 --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAdd.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringAdd; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnCrmDealRecurringAdd extends AbstractEventRequest +{ + public const CODE = 'ONCRMDEALRECURRINGADD'; + + public function getPayload(): OnCrmDealRecurringAddPayload + { + return new OnCrmDealRecurringAddPayload($this->eventPayload['data']); + } +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAddPayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAddPayload.php new file mode 100644 index 00000000..f68eac0c --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAddPayload.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringAdd; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read array{ + * ID: int, + * RECURRING_DEAL_ID: int, + * } $FIELDS + */ +class OnCrmDealRecurringAddPayload extends AbstractItem +{ +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDelete.php b/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDelete.php new file mode 100644 index 00000000..e3bef24e --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDelete.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringDelete; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnCrmDealRecurringDelete extends AbstractEventRequest +{ + public const CODE = 'ONCRMDEALRECURRINGDELETE'; + + public function getPayload(): OnCrmDealRecurringDeletePayload + { + return new OnCrmDealRecurringDeletePayload($this->eventPayload['data']); + } +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDeletePayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDeletePayload.php new file mode 100644 index 00000000..2745244e --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDeletePayload.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringDelete; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read array{ + * ID: int, + * } $FIELDS + */ +class OnCrmDealRecurringDeletePayload extends AbstractItem +{ +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdate.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdate.php new file mode 100644 index 00000000..4370686b --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdate.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringUpdate; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnCrmDealRecurringUpdate extends AbstractEventRequest +{ + public const CODE = 'ONCRMDEALRECURRINGUPDATE'; + + public function getPayload(): OnCrmDealRecurringUpdatePayload + { + return new OnCrmDealRecurringUpdatePayload($this->eventPayload['data']); + } +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdatePayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdatePayload.php new file mode 100644 index 00000000..592a5cf6 --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdatePayload.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringUpdate; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read array{ + * ID: int, + * RECURRING_DEAL_ID: int, + * } $FIELDS + */ +class OnCrmDealRecurringUpdatePayload extends AbstractItem +{ +} diff --git a/src/Services/CRM/Quote/Result/QuoteItemResult.php b/src/Services/CRM/Quote/Result/QuoteItemResult.php new file mode 100644 index 00000000..3c1b6e86 --- /dev/null +++ b/src/Services/CRM/Quote/Result/QuoteItemResult.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Result; + +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Email; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\InstantMessenger; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Phone; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Website; +use Carbon\CarbonImmutable; +use Money\Currency; +use Money\Money; + +/** + * Class LeadItemResult + * + * @property-read int $ID + * @property-read string $TITLE + * @property-read string|null $HONORIFIC + * @property-read string|null $NAME + * @property-read string|null $SECOND_NAME + * @property-read string|null $LAST_NAME + * @property-read CarbonImmutable|null $BIRTHDATE + * @property-read string|null $COMPANY_TITLE + * @property-read string|null $SOURCE_ID + * @property-read string|null $SOURCE_DESCRIPTION + * @property-read string|null $STATUS_ID + * @property-read string|null $STATUS_DESCRIPTION + * @property-read string|null $STATUS_SEMANTIC_ID + * @property-read string|null $POST + * @property-read string|null $ADDRESS + * @property-read string|null $ADDRESS_2 + * @property-read string|null $ADDRESS_CITY + * @property-read string|null $ADDRESS_POSTAL_CODE + * @property-read string|null $ADDRESS_REGION + * @property-read string|null $ADDRESS_PROVINCE + * @property-read string|null $ADDRESS_COUNTRY + * @property-read string|null $ADDRESS_COUNTRY_CODE + * @property-read int|null $ADDRESS_LOC_ADDR_ID + * @property-read Currency|null $CURRENCY_ID + * @property-read Money|null $OPPORTUNITY + * @property-read bool|null $IS_MANUAL_OPPORTUNITY + * @property-read bool|null $OPENED + * @property-read string|null $COMMENTS + * @property-read bool|null $HAS_PHONE + * @property-read bool|null $HAS_EMAIL + * @property-read bool|null $HAS_IMOL + * @property-read int|null $ASSIGNED_BY_ID + * @property-read int|null $CREATED_BY_ID + * @property-read int|null $MODIFY_BY_ID + * @property-read int|null $MOVED_BY_ID + * @property-read CarbonImmutable|null $DATE_CREATE + * @property-read CarbonImmutable|null $DATE_MODIFY + * @property-read CarbonImmutable|null $MOVED_TIME + * @property-read int|null $COMPANY_ID + * @property-read int|null $CONTACT_ID + * @property-read array|null $CONTACT_IDS + * @property-read bool|null $IS_RETURN_CUSTOMER + * @property-read CarbonImmutable|null $DATE_CLOSED + * @property-read string|null $ORIGINATOR_ID + * @property-read string|null $ORIGIN_ID + * @property-read string|null $UTM_SOURCE + * @property-read string|null $UTM_MEDIUM + * @property-read string|null $UTM_CAMPAIGN + * @property-read string|null $UTM_CONTENT + * @property-read string|null $UTM_TERM + * @property-read Phone[]|null $PHONE + * @property-read Email[]|null $EMAIL + * @property-read Website[]|null $WEB + * @property-read InstantMessenger[]|null $IM + * @property-read array|null $LINK + * @property-read int|null $LAST_ACTIVITY_BY + * @property-read CarbonImmutable|null $LAST_ACTIVITY_TIME + */ +class LeadItemResult extends AbstractCrmItem +{ + /** + * @param string $userfieldName + * + * @return mixed|null + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException + */ + public function getUserfieldByFieldName(string $userfieldName) + { + return $this->getKeyWithUserfieldByFieldName($userfieldName); + } +} diff --git a/src/Services/CRM/Quote/Result/QuoteResult.php b/src/Services/CRM/Quote/Result/QuoteResult.php new file mode 100644 index 00000000..872f4f0b --- /dev/null +++ b/src/Services/CRM/Quote/Result/QuoteResult.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class LeadResult + * + * @package Bitrix24\SDK\Services\CRM\Lead\Result + */ +class LeadResult extends AbstractResult +{ + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function lead(): LeadItemResult + { + return new LeadItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} diff --git a/src/Services/CRM/Quote/Result/QuoteUserfieldItemResult.php b/src/Services/CRM/Quote/Result/QuoteUserfieldItemResult.php new file mode 100644 index 00000000..1039703d --- /dev/null +++ b/src/Services/CRM/Quote/Result/QuoteUserfieldItemResult.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Result; + +use Bitrix24\SDK\Services\CRM\Userfield\Result\AbstractUserfieldItemResult; + +class LeadUserfieldItemResult extends AbstractUserfieldItemResult +{ +} diff --git a/src/Services/CRM/Quote/Result/QuoteUserfieldResult.php b/src/Services/CRM/Quote/Result/QuoteUserfieldResult.php new file mode 100644 index 00000000..fa4def56 --- /dev/null +++ b/src/Services/CRM/Quote/Result/QuoteUserfieldResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class LeadUserfieldResult extends AbstractResult +{ + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function userfieldItem(): LeadUserfieldItemResult + { + return new LeadUserfieldItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} diff --git a/src/Services/CRM/Quote/Result/QuoteUserfieldsResult.php b/src/Services/CRM/Quote/Result/QuoteUserfieldsResult.php new file mode 100644 index 00000000..eb837e18 --- /dev/null +++ b/src/Services/CRM/Quote/Result/QuoteUserfieldsResult.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class LeadUserfieldsResult extends AbstractResult +{ + /** + * @return \Bitrix24\SDK\Services\CRM\Lead\Result\LeadUserfieldItemResult[] + * @throws BaseException + */ + public function getUserfields(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new LeadUserfieldItemResult($item); + } + + return $res; + } +} diff --git a/src/Services/CRM/Quote/Result/QuotesResult.php b/src/Services/CRM/Quote/Result/QuotesResult.php new file mode 100644 index 00000000..17aec251 --- /dev/null +++ b/src/Services/CRM/Quote/Result/QuotesResult.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class LeadsResult + * + * @package Bitrix24\SDK\Services\CRM\Lead\Result + */ +class LeadsResult extends AbstractResult +{ + /** + * @return LeadItemResult[] + * @throws BaseException + */ + public function getLeads(): array + { + $items = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $items[] = new LeadItemResult($item); + } + + return $items; + } +} diff --git a/src/Services/CRM/Quote/Service/Batch.php b/src/Services/CRM/Quote/Service/Batch.php new file mode 100644 index 00000000..4403419b --- /dev/null +++ b/src/Services/CRM/Quote/Service/Batch.php @@ -0,0 +1,249 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Service; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AddedItemBatchResult; +use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; +use Bitrix24\SDK\Services\CRM\Quote\Result\QuoteItemResult; +use Generator; +use Psr\Log\LoggerInterface; + +#[ApiBatchServiceMetadata(new Scope(['crm']))] +class Batch +{ + protected BatchOperationsInterface $batch; + protected LoggerInterface $log; + + /** + * Batch constructor. + * + * @param BatchOperationsInterface $batch + * @param LoggerInterface $log + */ + public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) + { + $this->batch = $batch; + $this->log = $log; + } + + /** + * Batch list method for quotes + * + * @param array{ + * ID?: string, + * TITLE?: string, + * TYPE_ID?: string, + * CATEGORY_ID?: string, + * STAGE_ID?: string, + * STAGE_SEMANTIC_ID?: string, + * IS_NEW?: string, + * IS_RECURRING?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * PROBABILITY?: string, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * LEAD_ID?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * } $order + * + * @param array{ + * ID?: int, + * TITLE?: string, + * TYPE_ID?: string, + * CATEGORY_ID?: string, + * STAGE_ID?: string, + * STAGE_SEMANTIC_ID?: string, + * IS_NEW?: string, + * IS_RECURRING?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * PROBABILITY?: int, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * LEAD_ID?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * } $filter + * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','PROBABILITY','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','COMPANY_ID','CONTACT_ID','CONTACT_IDS','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','SOURCE_ID','SOURCE_DESCRIPTION','LEAD_ID','ADDITIONAL_INFO','LOCATION_ID','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] + * @param int|null $limit + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.quote.list', + 'https://training.bitrix24.com/rest_help/crm/quotes/crm_quote_list.php', + 'Batch list method for quotes' + )] + public function list(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug( + 'batchList', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + foreach ($this->batch->getTraversableList('crm.quote.list', $order, $filter, $select, $limit) as $key => $value) { + yield $key => new QuoteItemResult($value); + } + } + + /** + * Batch adding quotes + * + * @param array $quotes + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.quote.add', + 'https://training.bitrix24.com/rest_help/crm/quotes/crm_quote_add.php', + 'Batch adding quotes' + )] + public function add(array $quotes): Generator + { + $items = []; + foreach ($quotes as $quote) { + $items[] = [ + 'fields' => $quote, + ]; + } + foreach ($this->batch->addEntityItems('crm.quote.add', $items) as $key => $item) { + yield $key => new AddedItemBatchResult($item); + } + } + + /** + * Batch delete quotes + * + * @param int[] $quoteId + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.quote.delete', + 'https://training.bitrix24.com/rest_help/crm/quotes/crm_quote_delete.php', + 'Batch delete quotes' + )] + public function delete(array $quoteId): Generator + { + foreach ($this->batch->deleteEntityItems('crm.quote.delete', $quoteId) as $key => $item) { + yield $key => new DeletedItemBatchResult($item); + } + } +} diff --git a/src/Services/CRM/Quote/Service/Quote.php b/src/Services/CRM/Quote/Service/Quote.php new file mode 100644 index 00000000..b3b2bceb --- /dev/null +++ b/src/Services/CRM/Quote/Service/Quote.php @@ -0,0 +1,324 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Quote\Result\QuoteResult; +use Bitrix24\SDK\Services\CRM\Quote\Result\QuotesResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['crm']))] +class Quote extends AbstractService +{ + public Batch $batch; + + /** + * Quote constructor. + * + * @param Batch $batch + * @param CoreInterface $core + * @param LoggerInterface $log + */ + public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $log) + { + parent::__construct($core, $log); + $this->batch = $batch; + } + + /** + * add new quote + * + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-add.html + * + * @param array{ + * ID?: int, + * ASSIGNED_BY_ID?: int, + * BEGINDATA?: string, + * CLIENT_ADDR?: string, + * CLOSED?: bool, + * CLOSEDATA?: string, + * COMMENTS?: string, + * COMPANY_ID?: int, + * CONTACT_ID?: int, + * CONTACT_IDS?: int[], + * CONTENT?: string, + * CREATED_BY_ID?: int, + * CURRENCY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * DEAL_ID?: int, + * LEAD_ID?: int, + * LOCATION_ID?: int, + * MODIFY_BY_ID?: int, + * MYCOMPANY_ID?: int, + * OPENED?: bool, + * OPPORTUNITY?: string, + * PERSON_TYPE_ID?: int, + * QUOTE_NUMBER?: string, + * STATUS_ID?: string, + * TAX_VALUE?: string, + * TERMS?: string, + * TITLE?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_MEDIUM?: string, + * UTM_SOURCE?: string, + * UTM_TERM?: string, + * } $fields + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.quote.add', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-add.html', + 'Method adds new quote' + )] + public function add(array $fields): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.quote.add', + [ + 'fields' => $fields + ] + ) + ); + } + + /** + * Deletes the specified quote and all the associated objects. + * + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-delete.html + * + * @param int $id + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.quote.delete', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-delete.html', + 'Deletes the specified quote and all the associated objects.' + )] + public function delete(int $id): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.quote.delete', + [ + 'id' => $id, + ] + ) + ); + } + + /** + * Returns the description of the quote fields, including user fields. + * + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-fields.html + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.quote.fields', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-fields.html', + 'Returns the description of the quote fields, including user fields.' + )] + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.quote.fields')); + } + + /** + * Returns a quote by the quote ID. + * + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-get.html + * + * @param int $id + * + * @return QuoteResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.quote.get', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-get.html', + 'Returns a quote by the quote ID.' + )] + public function get(int $id): QuoteResult + { + return new QuoteResult($this->core->call('crm.quote.get', ['id' => $id])); + } + + /** + * Get list of quote items. + * + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-list.html + * + * @param array $order - order of quote items + * @param array $filter - filter array + * @param array $select = ['ID','ASSIGNED_BY_ID','BEGINDATA','CLIENT_ADDR','CLOSED','CLOSEDATA','COMMENTS','COMPANY_ID','CONTACT_ID','CONTACT_IDS','CONTENT','CREATED_BY_ID','CURRENCY_ID','DATE_CREATE','DATE_MODIFY','DEAL_ID','LEAD_ID','LOCATION_ID','MODIFY_BY_ID','MYCOMPANY_ID','OPENED','OPPORTUNITY','PERSON_TYPE_ID','QUOTE_NUMBER','STATUS_ID','TAX_VALUE','TERMS','TITLE','UTM_CAMPAIGN','UTM_CONTENT','UTM_MEDIUM','UTM_SOURCE','UTM_TERM'] + * @param integer $startItem - entity number to start from (usually returned in 'next' field of previous 'crm.quote.list' API call) + * + * @throws BaseException + * @throws TransportException + * @return QuotesResult + */ + #[ApiEndpointMetadata( + 'crm.quote.list', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-list.html', + 'Get list of quote items.' + )] + public function list(array $order, array $filter, array $select, int $startItem = 0): QuotesResult + { + return new QuotesResult( + $this->core->call( + 'crm.quote.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ) + ); + } + + /** + * Updates the specified (existing) quote. + * + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-update.html + * + * @param int $id + * @param array{ + * ID?: int, + * ASSIGNED_BY_ID?: int, + * BEGINDATA?: string, + * CLIENT_ADDR?: string, + * CLOSED?: bool, + * CLOSEDATA?: string, + * COMMENTS?: string, + * COMPANY_ID?: int, + * CONTACT_ID?: int, + * CONTACT_IDS?: int[], + * CONTENT?: string, + * CREATED_BY_ID?: int, + * CURRENCY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * DEAL_ID?: int, + * LEAD_ID?: int, + * LOCATION_ID?: int, + * MODIFY_BY_ID?: int, + * MYCOMPANY_ID?: int, + * OPENED?: bool, + * OPPORTUNITY?: string, + * PERSON_TYPE_ID?: int, + * QUOTE_NUMBER?: string, + * STATUS_ID?: string, + * TAX_VALUE?: string, + * TERMS?: string, + * TITLE?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_MEDIUM?: string, + * UTM_SOURCE?: string, + * UTM_TERM?: string, + * } $fields + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.quote.update', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-update.html', + 'Updates the specified (existing) quote.' + )] + public function update(int $id, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.quote.update', + [ + 'id' => $id, + 'fields' => $fields + ] + ) + ); + } + + /** + * Count quotes by filter + * + * @param array{ + * ID?: int, + * ASSIGNED_BY_ID?: int, + * BEGINDATA?: string, + * CLIENT_ADDR?: string, + * CLOSED?: bool, + * CLOSEDATA?: string, + * COMMENTS?: string, + * COMPANY_ID?: int, + * CONTACT_ID?: int, + * CONTACT_IDS?: int[], + * CONTENT?: string, + * CREATED_BY_ID?: int, + * CURRENCY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * DEAL_ID?: int, + * LEAD_ID?: int, + * LOCATION_ID?: int, + * MODIFY_BY_ID?: int, + * MYCOMPANY_ID?: int, + * OPENED?: bool, + * OPPORTUNITY?: string, + * PERSON_TYPE_ID?: int, + * QUOTE_NUMBER?: string, + * STATUS_ID?: string, + * TAX_VALUE?: string, + * TERMS?: string, + * TITLE?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_MEDIUM?: string, + * UTM_SOURCE?: string, + * UTM_TERM?: string, + * } $filter + * + * @return int + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function countByFilter(array $filter = []): int + { + return $this->list([], $filter, ['ID'], 1)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + } +} diff --git a/src/Services/CRM/Quote/Service/QuoteUserfield.php b/src/Services/CRM/Quote/Service/QuoteUserfield.php new file mode 100644 index 00000000..e497e47e --- /dev/null +++ b/src/Services/CRM/Quote/Service/QuoteUserfield.php @@ -0,0 +1,236 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Lead\Result\LeadUserfieldResult; +use Bitrix24\SDK\Services\CRM\Lead\Result\LeadUserfieldsResult; +use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException; +use Bitrix24\SDK\Services\CRM\Userfield\Service\UserfieldConstraints; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['crm']))] +class LeadUserfield extends AbstractService +{ + public function __construct(private readonly UserfieldConstraints $userfieldConstraints, CoreInterface $core, LoggerInterface $logger) + { + parent::__construct($core, $logger); + } + + /** + * Returns list of user lead fields by filter. + * + * @param array{ + * ID?: string, + * ENTITY_ID?: string, + * FIELD_NAME?: string, + * USER_TYPE_ID?: string, + * XML_ID?: string, + * SORT?: string, + * MULTIPLE?: string, + * MANDATORY?: string, + * SHOW_FILTER?: string, + * SHOW_IN_LIST?: string, + * EDIT_IN_LIST?: string, + * IS_SEARCHABLE?: string, + * EDIT_FORM_LABEL?: string, + * LIST_COLUMN_LABEL?: string, + * LIST_FILTER_LABEL?: string, + * ERROR_MESSAGE?: string, + * HELP_MESSAGE?: string, + * LIST?: string, + * SETTINGS?: string, + * } $order + * @param array{ + * ID?: string, + * ENTITY_ID?: string, + * FIELD_NAME?: string, + * USER_TYPE_ID?: string, + * XML_ID?: string, + * SORT?: string, + * MULTIPLE?: string, + * MANDATORY?: string, + * SHOW_FILTER?: string, + * SHOW_IN_LIST?: string, + * EDIT_IN_LIST?: string, + * IS_SEARCHABLE?: string, + * EDIT_FORM_LABEL?: string, + * LIST_COLUMN_LABEL?: string, + * LIST_FILTER_LABEL?: string, + * ERROR_MESSAGE?: string, + * HELP_MESSAGE?: string, + * LIST?: string, + * SETTINGS?: string, + * } $filter + * + * @throws BaseException + * @throws TransportException + * @link https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-list.html + */ + #[ApiEndpointMetadata( + 'crm.lead.userfield.list', + 'https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-list.html', + 'Returns list of user lead fields by filter.' + )] + public function list(array $order, array $filter): LeadUserfieldsResult + { + return new LeadUserfieldsResult( + $this->core->call( + 'crm.lead.userfield.list', + [ + 'order' => $order, + 'filter' => $filter, + ] + ) + ); + } + + /** + * Created new user field for leads. + * + * System limitation for field name - 20 characters. + * Prefix UF_CRM_is always added to the user field name. + * As a result, the actual name length - 13 characters. + * + * @param array{ + * FIELD_NAME?: string, + * USER_TYPE_ID?: string, + * XML_ID?: string, + * SORT?: string, + * MULTIPLE?: string, + * MANDATORY?: string, + * SHOW_FILTER?: string, + * SHOW_IN_LIST?: string, + * EDIT_IN_LIST?: string, + * IS_SEARCHABLE?: string, + * EDIT_FORM_LABEL?: string|array, + * LIST_COLUMN_LABEL?: string|array, + * LIST_FILTER_LABEL?: string|array, + * ERROR_MESSAGE?: string, + * HELP_MESSAGE?: string, + * LIST?: string, + * SETTINGS?: array, + * } $userfieldItemFields + * + * @throws BaseException + * @throws TransportException + * @throws UserfieldNameIsTooLongException + * @link https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-add.html + * + */ + #[ApiEndpointMetadata( + 'crm.lead.userfield.add', + 'https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-add.html', + 'Created new user field for leads.' + )] + public function add(array $userfieldItemFields): AddedItemResult + { + $this->userfieldConstraints->validName($userfieldItemFields['FIELD_NAME']); + + return new AddedItemResult( + $this->core->call( + 'crm.lead.userfield.add', + [ + 'fields' => $userfieldItemFields, + ] + ) + ); + } + + /** + * Deleted userfield for leads + * + * + * @throws BaseException + * @throws TransportException + * @link https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-delete.html + * + */ + #[ApiEndpointMetadata( + 'crm.lead.userfield.delete', + 'https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-delete.html', + 'Deleted userfield for leads' + )] + public function delete(int $userfieldId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.lead.userfield.delete', + [ + 'id' => $userfieldId, + ] + ) + ); + } + + /** + * Returns a userfield for lead by ID. + * + * + * @throws BaseException + * @throws TransportException + * @link https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-get.html + */ + #[ApiEndpointMetadata( + 'crm.lead.userfield.get', + 'https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-get.html', + 'Returns a userfield for lead by ID.' + )] + public function get(int $userfieldItemId): LeadUserfieldResult + { + return new LeadUserfieldResult( + $this->core->call( + 'crm.lead.userfield.get', + [ + 'id' => $userfieldItemId, + ] + ) + ); + } + + /** + * Updates an existing user field for leads. + * + * + * @throws BaseException + * @throws TransportException + * @link https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-update.html + */ + #[ApiEndpointMetadata( + 'crm.lead.userfield.update', + 'https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-update.html', + 'Updates an existing user field for leads.' + )] + public function update(int $userfieldItemId, array $userfieldFieldsToUpdate): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.lead.userfield.update', + [ + 'id' => $userfieldItemId, + 'fields' => $userfieldFieldsToUpdate, + ] + ) + ); + } +} From a91e7d5f925ddb84eaa195cc02e21111752d4ceb Mon Sep 17 00:00:00 2001 From: Vadim Soluyanov Date: Wed, 18 Jun 2025 16:48:44 +0400 Subject: [PATCH 2/8] add Batch and QuoteUserfields --- src/Services/CRM/Quote/Service/Batch.php | 245 +++++++++--------- .../CRM/Quote/Service/QuoteUserfield.php | 76 +++--- 2 files changed, 161 insertions(+), 160 deletions(-) diff --git a/src/Services/CRM/Quote/Service/Batch.php b/src/Services/CRM/Quote/Service/Batch.php index 4403419b..772d89d5 100644 --- a/src/Services/CRM/Quote/Service/Batch.php +++ b/src/Services/CRM/Quote/Service/Batch.php @@ -20,6 +20,7 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; +use Bitrix24\SDK\Core\Result\UpdatedItemBatchResult; use Bitrix24\SDK\Services\CRM\Quote\Result\QuoteItemResult; use Generator; use Psr\Log\LoggerInterface; @@ -46,93 +47,77 @@ public function __construct(BatchOperationsInterface $batch, LoggerInterface $lo * Batch list method for quotes * * @param array{ - * ID?: string, - * TITLE?: string, - * TYPE_ID?: string, - * CATEGORY_ID?: string, - * STAGE_ID?: string, - * STAGE_SEMANTIC_ID?: string, - * IS_NEW?: string, - * IS_RECURRING?: string, - * IS_RETURN_CUSTOMER?: string, - * IS_REPEATED_APPROACH?: string, - * PROBABILITY?: string, - * CURRENCY_ID?: string, - * OPPORTUNITY?: string, - * IS_MANUAL_OPPORTUNITY?: string, - * TAX_VALUE?: string, - * COMPANY_ID?: string, - * CONTACT_ID?: string, - * CONTACT_IDS?: string, - * QUOTE_ID?: string, - * BEGINDATE?: string, - * CLOSEDATE?: string, - * OPENED?: string, - * CLOSED?: string, - * COMMENTS?: string, - * ASSIGNED_BY_ID?: string, - * CREATED_BY_ID?: string, - * MODIFY_BY_ID?: string, - * DATE_CREATE?: string, - * DATE_MODIFY?: string, - * SOURCE_ID?: string, - * SOURCE_DESCRIPTION?: string, - * LEAD_ID?: string, - * ADDITIONAL_INFO?: string, - * LOCATION_ID?: string, - * ORIGINATOR_ID?: string, - * ORIGIN_ID?: string, - * UTM_SOURCE?: string, - * UTM_MEDIUM?: string, - * UTM_CAMPAIGN?: string, - * UTM_CONTENT?: string, - * UTM_TERM?: string, - * } $order + * ID?: int, + * ASSIGNED_BY_ID?: int, + * BEGINDATA?: string, + * CLIENT_ADDR?: string, + * CLOSED?: bool, + * CLOSEDATA?: string, + * COMMENTS?: string, + * COMPANY_ID?: int, + * CONTACT_ID?: int, + * CONTACT_IDS?: int[], + * CONTENT?: string, + * CREATED_BY_ID?: int, + * CURRENCY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * DEAL_ID?: int, + * LEAD_ID?: int, + * LOCATION_ID?: int, + * MODIFY_BY_ID?: int, + * MYCOMPANY_ID?: int, + * OPENED?: bool, + * OPPORTUNITY?: string, + * PERSON_TYPE_ID?: int, + * QUOTE_NUMBER?: string, + * STATUS_ID?: string, + * TAX_VALUE?: string, + * TERMS?: string, + * TITLE?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_MEDIUM?: string, + * UTM_SOURCE?: string, + * UTM_TERM?: string, + * } $order * * @param array{ - * ID?: int, - * TITLE?: string, - * TYPE_ID?: string, - * CATEGORY_ID?: string, - * STAGE_ID?: string, - * STAGE_SEMANTIC_ID?: string, - * IS_NEW?: string, - * IS_RECURRING?: string, - * IS_RETURN_CUSTOMER?: string, - * IS_REPEATED_APPROACH?: string, - * PROBABILITY?: int, - * CURRENCY_ID?: string, - * OPPORTUNITY?: string, - * IS_MANUAL_OPPORTUNITY?: string, - * TAX_VALUE?: string, - * COMPANY_ID?: string, - * CONTACT_ID?: string, - * CONTACT_IDS?: string, - * QUOTE_ID?: string, - * BEGINDATE?: string, - * CLOSEDATE?: string, - * OPENED?: string, - * CLOSED?: string, - * COMMENTS?: string, - * ASSIGNED_BY_ID?: string, - * CREATED_BY_ID?: string, - * MODIFY_BY_ID?: string, - * DATE_CREATE?: string, - * DATE_MODIFY?: string, - * SOURCE_ID?: string, - * SOURCE_DESCRIPTION?: string, - * LEAD_ID?: string, - * ADDITIONAL_INFO?: string, - * LOCATION_ID?: string, - * ORIGINATOR_ID?: string, - * ORIGIN_ID?: string, - * UTM_SOURCE?: string, - * UTM_MEDIUM?: string, - * UTM_CAMPAIGN?: string, - * UTM_CONTENT?: string, - * UTM_TERM?: string, - * } $filter - * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','PROBABILITY','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','COMPANY_ID','CONTACT_ID','CONTACT_IDS','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','SOURCE_ID','SOURCE_DESCRIPTION','LEAD_ID','ADDITIONAL_INFO','LOCATION_ID','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] + * ID?: int, + * ASSIGNED_BY_ID?: int, + * BEGINDATA?: string, + * CLIENT_ADDR?: string, + * CLOSED?: bool, + * CLOSEDATA?: string, + * COMMENTS?: string, + * COMPANY_ID?: int, + * CONTACT_ID?: int, + * CONTACT_IDS?: int[], + * CONTENT?: string, + * CREATED_BY_ID?: int, + * CURRENCY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * DEAL_ID?: int, + * LEAD_ID?: int, + * LOCATION_ID?: int, + * MODIFY_BY_ID?: int, + * MYCOMPANY_ID?: int, + * OPENED?: bool, + * OPPORTUNITY?: string, + * PERSON_TYPE_ID?: int, + * QUOTE_NUMBER?: string, + * STATUS_ID?: string, + * TAX_VALUE?: string, + * TERMS?: string, + * TITLE?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_MEDIUM?: string, + * UTM_SOURCE?: string, + * UTM_TERM?: string, + * } $filter + * @param array $select = ['ID','ASSIGNED_BY_ID','BEGINDATA','CLIENT_ADDR','CLOSED','CLOSEDATA','COMMENTS','COMPANY_ID','CONTACT_ID','CONTACT_IDS','CONTENT','CREATED_BY_ID','CURRENCY_ID','DATE_CREATE','DATE_MODIFY','DEAL_ID','LEAD_ID','LOCATION_ID','MODIFY_BY_ID','MYCOMPANY_ID','OPENED','OPPORTUNITY','PERSON_TYPE_ID','QUOTE_NUMBER','STATUS_ID','TAX_VALUE','TERMS','TITLE','UTM_CAMPAIGN','UTM_CONTENT','UTM_MEDIUM','UTM_SOURCE','UTM_TERM'] * @param int|null $limit * * @return Generator @@ -140,7 +125,7 @@ public function __construct(BatchOperationsInterface $batch, LoggerInterface $lo */ #[ApiBatchMethodMetadata( 'crm.quote.list', - 'https://training.bitrix24.com/rest_help/crm/quotes/crm_quote_list.php', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-list.html', 'Batch list method for quotes' )] public function list(array $order, array $filter, array $select, ?int $limit = null): Generator @@ -164,45 +149,37 @@ public function list(array $order, array $filter, array $select, ?int $limit = n * * @param array $quotes * @@ -211,7 +188,7 @@ public function list(array $order, array $filter, array $select, ?int $limit = n */ #[ApiBatchMethodMetadata( 'crm.quote.add', - 'https://training.bitrix24.com/rest_help/crm/quotes/crm_quote_add.php', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-add.html', 'Batch adding quotes' )] public function add(array $quotes): Generator @@ -226,6 +203,30 @@ public function add(array $quotes): Generator yield $key => new AddedItemBatchResult($item); } } + + /** + * Batch update quotes + * + * Update elements in array with structure + * element_id => [ // quote id + * 'fields' => [] // quote fields to update + * ] + * + * @param array $entityItems + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.quote.update', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-update.html', + 'Update in batch mode a list of quotes' + )] + public function update(array $entityItems): Generator + { + foreach ($this->batch->updateEntityItems('crm.quote.update', $entityItems) as $key => $item) { + yield $key => new UpdatedItemBatchResult($item); + } + } /** * Batch delete quotes @@ -237,7 +238,7 @@ public function add(array $quotes): Generator */ #[ApiBatchMethodMetadata( 'crm.quote.delete', - 'https://training.bitrix24.com/rest_help/crm/quotes/crm_quote_delete.php', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-delete.html', 'Batch delete quotes' )] public function delete(array $quoteId): Generator diff --git a/src/Services/CRM/Quote/Service/QuoteUserfield.php b/src/Services/CRM/Quote/Service/QuoteUserfield.php index e497e47e..1de5a51c 100644 --- a/src/Services/CRM/Quote/Service/QuoteUserfield.php +++ b/src/Services/CRM/Quote/Service/QuoteUserfield.php @@ -11,7 +11,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Lead\Service; +namespace Bitrix24\SDK\Services\CRM\Quote\Service; use Bitrix24\SDK\Attributes\ApiEndpointMetadata; use Bitrix24\SDK\Attributes\ApiServiceMetadata; @@ -23,14 +23,14 @@ use Bitrix24\SDK\Core\Result\DeletedItemResult; use Bitrix24\SDK\Core\Result\UpdatedItemResult; use Bitrix24\SDK\Services\AbstractService; -use Bitrix24\SDK\Services\CRM\Lead\Result\LeadUserfieldResult; -use Bitrix24\SDK\Services\CRM\Lead\Result\LeadUserfieldsResult; +use Bitrix24\SDK\Services\CRM\Quote\Result\QuoteUserfieldResult; +use Bitrix24\SDK\Services\CRM\Quote\Result\QuoteUserfieldsResult; use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException; use Bitrix24\SDK\Services\CRM\Userfield\Service\UserfieldConstraints; use Psr\Log\LoggerInterface; #[ApiServiceMetadata(new Scope(['crm']))] -class LeadUserfield extends AbstractService +class QuoteUserfield extends AbstractService { public function __construct(private readonly UserfieldConstraints $userfieldConstraints, CoreInterface $core, LoggerInterface $logger) { @@ -38,7 +38,7 @@ public function __construct(private readonly UserfieldConstraints $userfieldCons } /** - * Returns list of user lead fields by filter. + * Returns list of user quote fields by filter. * * @param array{ * ID?: string, @@ -85,18 +85,18 @@ public function __construct(private readonly UserfieldConstraints $userfieldCons * * @throws BaseException * @throws TransportException - * @link https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-list.html + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/user-field/crm-quote-user-field-list.html */ #[ApiEndpointMetadata( - 'crm.lead.userfield.list', - 'https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-list.html', - 'Returns list of user lead fields by filter.' + 'crm.quote.userfield.list', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/user-field/crm-quote-user-field-list.html', + 'Returns list of user quote fields by filter.' )] - public function list(array $order, array $filter): LeadUserfieldsResult + public function list(array $order, array $filter): QuoteUserfieldsResult { - return new LeadUserfieldsResult( + return new QuoteUserfieldsResult( $this->core->call( - 'crm.lead.userfield.list', + 'crm.quote.userfield.list', [ 'order' => $order, 'filter' => $filter, @@ -106,7 +106,7 @@ public function list(array $order, array $filter): LeadUserfieldsResult } /** - * Created new user field for leads. + * Created new user field for quotes. * * System limitation for field name - 20 characters. * Prefix UF_CRM_is always added to the user field name. @@ -135,13 +135,13 @@ public function list(array $order, array $filter): LeadUserfieldsResult * @throws BaseException * @throws TransportException * @throws UserfieldNameIsTooLongException - * @link https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-add.html + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/user-field/crm-quote-user-field-add.html * */ #[ApiEndpointMetadata( - 'crm.lead.userfield.add', - 'https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-add.html', - 'Created new user field for leads.' + 'crm.quote.userfield.add', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/user-field/crm-quote-user-field-add.html', + 'Created new user field for quotes.' )] public function add(array $userfieldItemFields): AddedItemResult { @@ -149,7 +149,7 @@ public function add(array $userfieldItemFields): AddedItemResult return new AddedItemResult( $this->core->call( - 'crm.lead.userfield.add', + 'crm.quote.userfield.add', [ 'fields' => $userfieldItemFields, ] @@ -158,24 +158,24 @@ public function add(array $userfieldItemFields): AddedItemResult } /** - * Deleted userfield for leads + * Deleted userfield for quotes * * * @throws BaseException * @throws TransportException - * @link https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-delete.html + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/user-field/crm-quote-user-field-delete.html * */ #[ApiEndpointMetadata( - 'crm.lead.userfield.delete', - 'https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-delete.html', - 'Deleted userfield for leads' + 'crm.quote.userfield.delete', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/user-field/crm-quote-user-field-delete.html', + 'Deleted userfield for quotes' )] public function delete(int $userfieldId): DeletedItemResult { return new DeletedItemResult( $this->core->call( - 'crm.lead.userfield.delete', + 'crm.quote.userfield.delete', [ 'id' => $userfieldId, ] @@ -184,23 +184,23 @@ public function delete(int $userfieldId): DeletedItemResult } /** - * Returns a userfield for lead by ID. + * Returns a userfield for quote by ID. * * * @throws BaseException * @throws TransportException - * @link https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-get.html + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/user-field/crm-quote-user-field-get.html */ #[ApiEndpointMetadata( - 'crm.lead.userfield.get', - 'https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-get.html', - 'Returns a userfield for lead by ID.' + 'crm.quote.userfield.get', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/user-field/crm-quote-user-field-get.html', + 'Returns a userfield for quote by ID.' )] - public function get(int $userfieldItemId): LeadUserfieldResult + public function get(int $userfieldItemId): QuoteUserfieldResult { - return new LeadUserfieldResult( + return new QuoteUserfieldResult( $this->core->call( - 'crm.lead.userfield.get', + 'crm.quote.userfield.get', [ 'id' => $userfieldItemId, ] @@ -209,23 +209,23 @@ public function get(int $userfieldItemId): LeadUserfieldResult } /** - * Updates an existing user field for leads. + * Updates an existing user field for quotes. * * * @throws BaseException * @throws TransportException - * @link https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-update.html + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/user-field/crm-quote-user-field-update.html */ #[ApiEndpointMetadata( - 'crm.lead.userfield.update', - 'https://apidocs.bitrix24.com/api-reference/crm/leads/userfield/crm-lead-userfield-update.html', - 'Updates an existing user field for leads.' + 'crm.quote.userfield.update', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/user-field/crm-quote-user-field-update.html', + 'Updates an existing user field for quotes.' )] public function update(int $userfieldItemId, array $userfieldFieldsToUpdate): UpdatedItemResult { return new UpdatedItemResult( $this->core->call( - 'crm.lead.userfield.update', + 'crm.quote.userfield.update', [ 'id' => $userfieldItemId, 'fields' => $userfieldFieldsToUpdate, From 3b14ac49b00cd8150f20ac8218c539bfe55a90b7 Mon Sep 17 00:00:00 2001 From: Vadim Soluyanov Date: Thu, 19 Jun 2025 11:39:01 +0400 Subject: [PATCH 3/8] add new classes and tests --- .../Events/OnCrmQuoteAdd/OnCrmQuoteAdd.php | 10 +- .../OnCrmQuoteAdd/OnCrmQuoteAddPayload.php | 5 +- .../OnCrmQuoteDelete/OnCrmQuoteDelete.php | 10 +- .../OnCrmQuoteDeletePayload.php | 4 +- .../OnCrmQuoteUpdate/OnCrmQuoteUpdate.php | 10 +- .../QuoteContactConnectionItemResult.php | 25 +++ .../Result/QuoteContactConnectionResult.php | 35 ++++ .../CRM/Quote/Result/QuoteItemResult.php | 74 +++----- .../Result/QuoteProductRowItemResult.php | 54 ++++++ .../Result/QuoteProductRowItemsResult.php | 53 ++++++ src/Services/CRM/Quote/Result/QuoteResult.php | 14 +- .../Quote/Result/QuoteUserfieldItemResult.php | 4 +- .../CRM/Quote/Result/QuoteUserfieldResult.php | 8 +- .../Quote/Result/QuoteUserfieldsResult.php | 8 +- .../CRM/Quote/Result/QuotesResult.php | 16 +- .../CRM/Quote/Service/QuoteContact.php | 174 ++++++++++++++++++ .../CRM/Quote/Service/QuoteProductRows.php | 118 ++++++++++++ .../Services/CRM/Quote/Service/BatchTest.php | 111 +++++++++++ .../CRM/Quote/Service/QuoteContactTest.php | 171 +++++++++++++++++ .../Quote/Service/QuoteProductRowsTest.php | 146 +++++++++++++++ .../Services/CRM/Quote/Service/QuoteTest.php | 154 ++++++++++++++++ .../CRM/Quote/Service/QuoteUserfieldTest.php | 107 +++++++++++ .../Service/QuoteUserfieldUseCaseTest.php | 103 +++++++++++ 23 files changed, 1319 insertions(+), 95 deletions(-) create mode 100644 src/Services/CRM/Quote/Result/QuoteContactConnectionItemResult.php create mode 100644 src/Services/CRM/Quote/Result/QuoteContactConnectionResult.php create mode 100644 src/Services/CRM/Quote/Result/QuoteProductRowItemResult.php create mode 100644 src/Services/CRM/Quote/Result/QuoteProductRowItemsResult.php create mode 100644 src/Services/CRM/Quote/Service/QuoteContact.php create mode 100644 src/Services/CRM/Quote/Service/QuoteProductRows.php create mode 100644 tests/Integration/Services/CRM/Quote/Service/BatchTest.php create mode 100644 tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php create mode 100644 tests/Integration/Services/CRM/Quote/Service/QuoteProductRowsTest.php create mode 100644 tests/Integration/Services/CRM/Quote/Service/QuoteTest.php create mode 100644 tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldTest.php create mode 100644 tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldUseCaseTest.php diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAdd.php b/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAdd.php index 32d6cca6..baa91311 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAdd.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAdd.php @@ -11,16 +11,16 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringAdd; +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteAdd; use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; -class OnCrmDealRecurringAdd extends AbstractEventRequest +class OnCrmQuoteAdd extends AbstractEventRequest { - public const CODE = 'ONCRMDEALRECURRINGADD'; + public const CODE = 'ONCRMQUOTEADD'; - public function getPayload(): OnCrmDealRecurringAddPayload + public function getPayload(): OnCrmQuoteAddPayload { - return new OnCrmDealRecurringAddPayload($this->eventPayload['data']); + return new OnCrmQuoteAddPayload($this->eventPayload['data']); } } diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAddPayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAddPayload.php index f68eac0c..1a7ce1ad 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAddPayload.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteAdd/OnCrmQuoteAddPayload.php @@ -11,16 +11,15 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringAdd; +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteAdd; use Bitrix24\SDK\Core\Result\AbstractItem; /** * @property-read array{ * ID: int, - * RECURRING_DEAL_ID: int, * } $FIELDS */ -class OnCrmDealRecurringAddPayload extends AbstractItem +class OnCrmQuoteAddPayload extends AbstractItem { } diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDelete.php b/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDelete.php index e3bef24e..d12294b0 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDelete.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDelete.php @@ -11,16 +11,16 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringDelete; +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteDelete; use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; -class OnCrmDealRecurringDelete extends AbstractEventRequest +class OnCrmQuoteDelete extends AbstractEventRequest { - public const CODE = 'ONCRMDEALRECURRINGDELETE'; + public const CODE = 'ONCRMQUOTEDELETE'; - public function getPayload(): OnCrmDealRecurringDeletePayload + public function getPayload(): OnCrmQuoteDeletePayload { - return new OnCrmDealRecurringDeletePayload($this->eventPayload['data']); + return new OnCrmQuoteDeletePayload($this->eventPayload['data']); } } diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDeletePayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDeletePayload.php index 2745244e..74249ca1 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDeletePayload.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteDelete/OnCrmQuoteDeletePayload.php @@ -11,7 +11,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringDelete; +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteDelete; use Bitrix24\SDK\Core\Result\AbstractItem; @@ -20,6 +20,6 @@ * ID: int, * } $FIELDS */ -class OnCrmDealRecurringDeletePayload extends AbstractItem +class OnCrmQuoteDeletePayload extends AbstractItem { } diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdate.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdate.php index 4370686b..aab0d122 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdate.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdate.php @@ -11,16 +11,16 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringUpdate; +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUpdate; use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; -class OnCrmDealRecurringUpdate extends AbstractEventRequest +class OnCrmQuoteUpdate extends AbstractEventRequest { - public const CODE = 'ONCRMDEALRECURRINGUPDATE'; + public const CODE = 'ONCRMQUOTEUPDATE'; - public function getPayload(): OnCrmDealRecurringUpdatePayload + public function getPayload(): OnCrmQuoteUpdatePayload { - return new OnCrmDealRecurringUpdatePayload($this->eventPayload['data']); + return new OnCrmQuoteUpdatePayload($this->eventPayload['data']); } } diff --git a/src/Services/CRM/Quote/Result/QuoteContactConnectionItemResult.php b/src/Services/CRM/Quote/Result/QuoteContactConnectionItemResult.php new file mode 100644 index 00000000..43916b47 --- /dev/null +++ b/src/Services/CRM/Quote/Result/QuoteContactConnectionItemResult.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Result; + +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; + +/** + * @property-read int $CONTACT_ID + * @property-read int $SORT + * @property-read bool $IS_PRIMARY + */ +class QuoteContactConnectionItemResult extends AbstractCrmItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Quote/Result/QuoteContactConnectionResult.php b/src/Services/CRM/Quote/Result/QuoteContactConnectionResult.php new file mode 100644 index 00000000..fcc89f99 --- /dev/null +++ b/src/Services/CRM/Quote/Result/QuoteContactConnectionResult.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class QuoteContactConnectionResult extends AbstractResult +{ + /** + * @return QuoteContactConnectionItemResult[] + * @throws BaseException + */ + public function getContactConnections(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new QuoteContactConnectionItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Quote/Result/QuoteItemResult.php b/src/Services/CRM/Quote/Result/QuoteItemResult.php index 3c1b6e86..28ed5b2f 100644 --- a/src/Services/CRM/Quote/Result/QuoteItemResult.php +++ b/src/Services/CRM/Quote/Result/QuoteItemResult.php @@ -3,7 +3,7 @@ /** * This file is part of the bitrix24-php-sdk package. * - * © Maksim Mesilov + * © Vadim Soluyanov * * For the full copyright and license information, please view the MIT-LICENSE.txt * file that was distributed with this source code. @@ -11,7 +11,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Lead\Result; +namespace Bitrix24\SDK\Services\CRM\Quote\Result; use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Email; @@ -23,67 +23,41 @@ use Money\Money; /** - * Class LeadItemResult + * Class QuoteItemResult * * @property-read int $ID * @property-read string $TITLE - * @property-read string|null $HONORIFIC - * @property-read string|null $NAME - * @property-read string|null $SECOND_NAME - * @property-read string|null $LAST_NAME - * @property-read CarbonImmutable|null $BIRTHDATE - * @property-read string|null $COMPANY_TITLE - * @property-read string|null $SOURCE_ID - * @property-read string|null $SOURCE_DESCRIPTION - * @property-read string|null $STATUS_ID - * @property-read string|null $STATUS_DESCRIPTION - * @property-read string|null $STATUS_SEMANTIC_ID - * @property-read string|null $POST - * @property-read string|null $ADDRESS - * @property-read string|null $ADDRESS_2 - * @property-read string|null $ADDRESS_CITY - * @property-read string|null $ADDRESS_POSTAL_CODE - * @property-read string|null $ADDRESS_REGION - * @property-read string|null $ADDRESS_PROVINCE - * @property-read string|null $ADDRESS_COUNTRY - * @property-read string|null $ADDRESS_COUNTRY_CODE - * @property-read int|null $ADDRESS_LOC_ADDR_ID - * @property-read Currency|null $CURRENCY_ID - * @property-read Money|null $OPPORTUNITY - * @property-read bool|null $IS_MANUAL_OPPORTUNITY - * @property-read bool|null $OPENED - * @property-read string|null $COMMENTS - * @property-read bool|null $HAS_PHONE - * @property-read bool|null $HAS_EMAIL - * @property-read bool|null $HAS_IMOL * @property-read int|null $ASSIGNED_BY_ID - * @property-read int|null $CREATED_BY_ID - * @property-read int|null $MODIFY_BY_ID - * @property-read int|null $MOVED_BY_ID - * @property-read CarbonImmutable|null $DATE_CREATE - * @property-read CarbonImmutable|null $DATE_MODIFY - * @property-read CarbonImmutable|null $MOVED_TIME + * @property-read CarbonImmutable|null $BEGINDATA + * @property-read CarbonImmutable|null $CLOSEDATA + * @property-read string|null $CLIENT_ADDR + * @property-read bool|null $CLOSED + * @property-read string|null $COMMENTS * @property-read int|null $COMPANY_ID * @property-read int|null $CONTACT_ID * @property-read array|null $CONTACT_IDS - * @property-read bool|null $IS_RETURN_CUSTOMER - * @property-read CarbonImmutable|null $DATE_CLOSED - * @property-read string|null $ORIGINATOR_ID - * @property-read string|null $ORIGIN_ID + * @property-read string|null $CONTENT + * @property-read int|null $CREATED_BY_ID + * @property-read Currency|null $CURRENCY_ID + * @property-read CarbonImmutable|null $DATE_CREATE + * @property-read CarbonImmutable|null $DATE_MODIFY + * @property-read int|null $DEAL_ID + * @property-read int|null $LEAD_ID + * @property-read int|null $LOCATION_ID + * @property-read bool|null $OPENED + * @property-read Money|null $OPPORTUNITY + * @property-read int|null $PERSON_TYPE_ID + * @property-read string|null $QUOTE_NUMBER + * @property-read string|null $STATUS_ID + * @property-read string|null $TAX_VALUE + * @property-read string|null $TERMS * @property-read string|null $UTM_SOURCE * @property-read string|null $UTM_MEDIUM * @property-read string|null $UTM_CAMPAIGN * @property-read string|null $UTM_CONTENT * @property-read string|null $UTM_TERM - * @property-read Phone[]|null $PHONE - * @property-read Email[]|null $EMAIL - * @property-read Website[]|null $WEB - * @property-read InstantMessenger[]|null $IM - * @property-read array|null $LINK - * @property-read int|null $LAST_ACTIVITY_BY - * @property-read CarbonImmutable|null $LAST_ACTIVITY_TIME */ -class LeadItemResult extends AbstractCrmItem +class QuoteItemResult extends AbstractCrmItem { /** * @param string $userfieldName diff --git a/src/Services/CRM/Quote/Result/QuoteProductRowItemResult.php b/src/Services/CRM/Quote/Result/QuoteProductRowItemResult.php new file mode 100644 index 00000000..e0eb1897 --- /dev/null +++ b/src/Services/CRM/Quote/Result/QuoteProductRowItemResult.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Result; + +use Money\Money; +use MoneyPHP\Percentage\Percentage; +use Bitrix24\SDK\Services\CRM\Common\Result\DiscountType; +use Carbon\CarbonImmutable; +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; + +/** + * @property-read int $ID + * @property-read int $OWNER_ID + * @property-read string $OWNER_TYPE + * @property-read int $PRODUCT_ID + * @property-read string $PRODUCT_NAME + * @property-read string|null $ORIGINAL_PRODUCT_NAME + * @property-read string|null $PRODUCT_DESCRIPTION + * @property-read Money $PRICE price with taxes and discounts + * @property-read Money $PRICE_EXCLUSIVE without taxes but with discounts + * @property-read Money $PRICE_NETTO without taxes and discounts + * @property-read Money $PRICE_BRUTTO without discounts but with taxes + * @property-read Money $PRICE_ACCOUNT formatted price + * @property-read string $QUANTITY + * @property-read DiscountType $DISCOUNT_TYPE_ID + * @property-read Percentage $DISCOUNT_RATE + * @property-read Money $DISCOUNT_SUM + * @property-read string $TAX_RATE + * @property-read bool $TAX_INCLUDED + * @property-read string $CUSTOMIZED + * @property-read int $MEASURE_CODE + * @property-read string $MEASURE_NAME + * @property-read int $SORT + * @property-read string|null $XML_ID + * @property-read int $TYPE + * @property-read int|null $STORE_ID + * @property-read int|null $RESERVE_ID + * @property-read CarbonImmutable|null $DATE_RESERVE_END + * @property-read int|null $RESERVE_QUANTITY + */ +class QuoteProductRowItemResult extends AbstractCrmItem +{ +} diff --git a/src/Services/CRM/Quote/Result/QuoteProductRowItemsResult.php b/src/Services/CRM/Quote/Result/QuoteProductRowItemsResult.php new file mode 100644 index 00000000..b7412d5a --- /dev/null +++ b/src/Services/CRM/Quote/Result/QuoteProductRowItemsResult.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Response\Response; +use Bitrix24\SDK\Core\Result\AbstractResult; +use Money\Currency; + +/** + * Class QuoteProductRowItemsResult + * + * @package Bitrix24\SDK\Services\CRM\Quote\Result + */ +class QuoteProductRowItemsResult extends AbstractResult +{ + public function __construct(Response $coreResponse, private readonly Currency $currency) + { + parent::__construct($coreResponse); + } + + /** + * @return QuoteProductRowItemResult[] + * @throws BaseException + */ + public function getProductRows(): array + { + $res = []; + if (!empty($this->getCoreResponse()->getResponseData()->getResult()['result']['rows'])) { + foreach ($this->getCoreResponse()->getResponseData()->getResult()['result']['rows'] as $productRow) { + $res[] = new QuoteProductRowItemResult($productRow, $this->currency); + } + } else { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $productRow) { + $res[] = new QuoteProductRowItemResult($productRow, $this->currency); + } + } + + return $res; + } +} diff --git a/src/Services/CRM/Quote/Result/QuoteResult.php b/src/Services/CRM/Quote/Result/QuoteResult.php index 872f4f0b..1cf4b9af 100644 --- a/src/Services/CRM/Quote/Result/QuoteResult.php +++ b/src/Services/CRM/Quote/Result/QuoteResult.php @@ -3,7 +3,7 @@ /** * This file is part of the bitrix24-php-sdk package. * - * © Maksim Mesilov + * © Vadim Soluyanov * * For the full copyright and license information, please view the MIT-LICENSE.txt * file that was distributed with this source code. @@ -12,22 +12,22 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Lead\Result; +namespace Bitrix24\SDK\Services\CRM\Quote\Result; use Bitrix24\SDK\Core\Result\AbstractResult; /** - * Class LeadResult + * Class QuoteResult * - * @package Bitrix24\SDK\Services\CRM\Lead\Result + * @package Bitrix24\SDK\Services\CRM\Quote\Result */ -class LeadResult extends AbstractResult +class QuoteResult extends AbstractResult { /** * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - public function lead(): LeadItemResult + public function quote(): QuoteItemResult { - return new LeadItemResult($this->getCoreResponse()->getResponseData()->getResult()); + return new QuoteItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } diff --git a/src/Services/CRM/Quote/Result/QuoteUserfieldItemResult.php b/src/Services/CRM/Quote/Result/QuoteUserfieldItemResult.php index 1039703d..9b8f0301 100644 --- a/src/Services/CRM/Quote/Result/QuoteUserfieldItemResult.php +++ b/src/Services/CRM/Quote/Result/QuoteUserfieldItemResult.php @@ -12,10 +12,10 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Lead\Result; +namespace Bitrix24\SDK\Services\CRM\Quote\Result; use Bitrix24\SDK\Services\CRM\Userfield\Result\AbstractUserfieldItemResult; -class LeadUserfieldItemResult extends AbstractUserfieldItemResult +class QuoteUserfieldItemResult extends AbstractUserfieldItemResult { } diff --git a/src/Services/CRM/Quote/Result/QuoteUserfieldResult.php b/src/Services/CRM/Quote/Result/QuoteUserfieldResult.php index fa4def56..b4cbe9f9 100644 --- a/src/Services/CRM/Quote/Result/QuoteUserfieldResult.php +++ b/src/Services/CRM/Quote/Result/QuoteUserfieldResult.php @@ -12,17 +12,17 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Lead\Result; +namespace Bitrix24\SDK\Services\CRM\Quote\Result; use Bitrix24\SDK\Core\Result\AbstractResult; -class LeadUserfieldResult extends AbstractResult +class QuoteUserfieldResult extends AbstractResult { /** * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - public function userfieldItem(): LeadUserfieldItemResult + public function userfieldItem(): QuoteUserfieldItemResult { - return new LeadUserfieldItemResult($this->getCoreResponse()->getResponseData()->getResult()); + return new QuoteUserfieldItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } diff --git a/src/Services/CRM/Quote/Result/QuoteUserfieldsResult.php b/src/Services/CRM/Quote/Result/QuoteUserfieldsResult.php index eb837e18..414091f0 100644 --- a/src/Services/CRM/Quote/Result/QuoteUserfieldsResult.php +++ b/src/Services/CRM/Quote/Result/QuoteUserfieldsResult.php @@ -12,22 +12,22 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Lead\Result; +namespace Bitrix24\SDK\Services\CRM\Quote\Result; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AbstractResult; -class LeadUserfieldsResult extends AbstractResult +class QuoteUserfieldsResult extends AbstractResult { /** - * @return \Bitrix24\SDK\Services\CRM\Lead\Result\LeadUserfieldItemResult[] + * @return \Bitrix24\SDK\Services\CRM\Quote\Result\QuoteUserfieldItemResult[] * @throws BaseException */ public function getUserfields(): array { $res = []; foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { - $res[] = new LeadUserfieldItemResult($item); + $res[] = new QuoteUserfieldItemResult($item); } return $res; diff --git a/src/Services/CRM/Quote/Result/QuotesResult.php b/src/Services/CRM/Quote/Result/QuotesResult.php index 17aec251..f676dade 100644 --- a/src/Services/CRM/Quote/Result/QuotesResult.php +++ b/src/Services/CRM/Quote/Result/QuotesResult.php @@ -3,7 +3,7 @@ /** * This file is part of the bitrix24-php-sdk package. * - * © Maksim Mesilov + * © Vadim Soluyanov * * For the full copyright and license information, please view the MIT-LICENSE.txt * file that was distributed with this source code. @@ -12,27 +12,27 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Lead\Result; +namespace Bitrix24\SDK\Services\CRM\Quote\Result; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AbstractResult; /** - * Class LeadsResult + * Class QuotesResult * - * @package Bitrix24\SDK\Services\CRM\Lead\Result + * @package Bitrix24\SDK\Services\CRM\Quote\Result */ -class LeadsResult extends AbstractResult +class QuotesResult extends AbstractResult { /** - * @return LeadItemResult[] + * @return QuoteItemResult[] * @throws BaseException */ - public function getLeads(): array + public function getQuotes(): array { $items = []; foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { - $items[] = new LeadItemResult($item); + $items[] = new QuoteItemResult($item); } return $items; diff --git a/src/Services/CRM/Quote/Service/QuoteContact.php b/src/Services/CRM/Quote/Service/QuoteContact.php new file mode 100644 index 00000000..00ad1ac0 --- /dev/null +++ b/src/Services/CRM/Quote/Service/QuoteContact.php @@ -0,0 +1,174 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Service; + +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Common\ContactConnection; +use Bitrix24\SDK\Services\CRM\Quote\Result\QuoteContactConnectionResult; +use Psr\Log\LoggerInterface; +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; + +#[ApiServiceMetadata(new Scope(['crm']))] +class QuoteContact extends AbstractService +{ + /** + * Get Field Descriptions for Estimate-Contact Connection + * + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/index.html + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.quote.contact.fields', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/index.html', + 'Get Field Descriptions for Estimate-Contact Connection' + )] + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.quote.contact.fields')); + } + + /** + * Set a set of contacts associated with the specified estimate + * + * @param non-negative-int $quoteId + * @param ContactConnection[] $contactConnections + * @throws InvalidArgumentException + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/index.html + */ + #[ApiEndpointMetadata( + 'crm.quote.contact.items.set', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/index.html', + 'Set a set of contacts associated with the specified estimate crm.quote.contact.items.set' + )] + public function setItems(int $quoteId, array $contactConnections): UpdatedItemResult + { + $items = []; + foreach ($contactConnections as $item) { + if (!$item instanceof ContactConnection) { + throw new InvalidArgumentException( + sprintf('array item «%s» must be «%s» type', gettype($item), ContactConnection::class) + ); + } + + $items[] = [ + 'CONTACT_ID' => $item->contactId, + 'SORT' => $item->sort, + 'IS_PRIMARY' => $item->isPrimary ? 'Y' : 'N' + ]; + } + if ($items === []) { + throw new InvalidArgumentException('empty contact connections array'); + } + + return new UpdatedItemResult( + $this->core->call('crm.quote.contact.items.set', [ + 'id' => $quoteId, + 'items' => $items + ]) + ); + } + + /** + * Get a set of contacts associated with the specified estimate + * + * @param non-negative-int $quoteId + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/index.html + */ + #[ApiEndpointMetadata( + 'crm.quote.contact.items.get', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/index.html', + 'Get a set of contacts associated with the specified estimate crm.quote.contact.items.get' + )] + public function get(int $quoteId): QuoteContactConnectionResult + { + return new QuoteContactConnectionResult($this->core->call('crm.quote.contact.items.get', [ + 'id' => $quoteId + ])); + } + + /** + * Get a set of contacts associated with the specified estimates + * + * @param non-negative-int $quoteId + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/index.html + */ + #[ApiEndpointMetadata( + 'crm.quote.contact.items.delete', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/index.html', + 'Clear the set of contacts associated with the specified estimate' + )] + public function deleteItems(int $quoteId): DeletedItemResult + { + return new DeletedItemResult($this->core->call('crm.quote.contact.items.delete', [ + 'id' => $quoteId + ])); + } + + /** + * Add Contact to the Specified Estimate + * + * @param non-negative-int $quoteId + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/index.html + */ + #[ApiEndpointMetadata( + 'crm.quote.contact.add', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/index.html', + 'Add Contact to the Specified Estimate' + )] + public function add(int $quoteId, ContactConnection $connection): UpdatedItemResult + { + return new UpdatedItemResult($this->core->call('crm.quote.contact.add', [ + 'id' => $quoteId, + 'fields' => [ + 'CONTACT_ID' => $connection->contactId, + 'SORT' => $connection->sort, + 'IS_PRIMARY' => $connection->isPrimary ? 'Y' : 'N' + ] + ])); + } + + /** + * Delete Contact from Specified Estimate + * + * @param non-negative-int $quoteId + * @param non-negative-int $contactId + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/index.html + */ + #[ApiEndpointMetadata( + 'crm.quote.contact.delete', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/index.html', + 'Delete Contact from Specified Estimate' + )] + public function delete(int $quoteId, int $contactId): DeletedItemResult + { + return new DeletedItemResult($this->core->call('crm.quote.contact.delete', [ + 'id' => $quoteId, + 'fields' => [ + 'CONTACT_ID' => $contactId + ] + ])); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Quote/Service/QuoteProductRows.php b/src/Services/CRM/Quote/Service/QuoteProductRows.php new file mode 100644 index 00000000..6a737f0b --- /dev/null +++ b/src/Services/CRM/Quote/Service/QuoteProductRows.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Quote\Result\QuoteProductRowItemsResult; +use Money\Currency; + +#[ApiServiceMetadata(new Scope(['crm']))] +class QuoteProductRows extends AbstractService +{ + /** + * Returns products inside the specified quote. + * + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-product-rows-get.html + * + * @param Currency|null $currency + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.quote.productrows.get', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-product-rows-get.html', + 'Returns products inside the specified quote.' + )] + public function get(int $quoteId, Currency $currency = null): QuoteProductRowItemsResult + { + if (!$currency instanceof \Money\Currency) { + $res = $this->core->call('batch', [ + 'halt' => 0, + 'cmd' => [ + 'quote' => sprintf('crm.quote.get?ID=%s', $quoteId), + 'rows' => sprintf('crm.quote.productrows.get?ID=%s', $quoteId) + ], + ]); + $data = $res->getResponseData()->getResult(); + $currency = new Currency($data['result']['quote']['CURRENCY_ID']); + return new QuoteProductRowItemsResult($res, $currency); + } + + return new QuoteProductRowItemsResult( + $this->core->call( + 'crm.quote.productrows.get', + [ + 'id' => $quoteId, + ] + ), + $currency + ); + } + + + /** + * Creates or updates product entries inside the specified quote. + * + * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-product-rows-set.html + * + * @param int $quoteId + * @param array $productRows + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.quote.productrows.set', + 'https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-product-rows-set.html', + 'Creates or updates product entries inside the specified quote.' + )] + public function set(int $quoteId, array $productRows): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.quote.productrows.set', + [ + 'id' => $quoteId, + 'rows' => $productRows, + ] + ) + ); + } +} diff --git a/tests/Integration/Services/CRM/Quote/Service/BatchTest.php b/tests/Integration/Services/CRM/Quote/Service/BatchTest.php new file mode 100644 index 00000000..c4404010 --- /dev/null +++ b/tests/Integration/Services/CRM/Quote/Service/BatchTest.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +/** + * Class BatchTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service + */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Lead\Service\Batch::class)] +class BatchTest extends TestCase +{ + protected Lead $leadService; + + /** + * @throws BaseException + * @throws TransportException + */ + #[\PHPUnit\Framework\Attributes\TestDox('Batch list leads')] + public function testBatchList(): void + { + $itemId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + $cnt = 0; + + foreach ($this->leadService->batch->list([], ['ID' => $itemId], ['ID', 'NAME'], 1) as $item) { + $cnt++; + } + + self::assertGreaterThanOrEqual(1, $cnt); + + $this->leadService->delete($itemId); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + #[\PHPUnit\Framework\Attributes\TestDox('Batch add lead')] + public function testBatchAdd(): void + { + $items = []; + for ($i = 1; $i < 60; $i++) { + $items[] = ['TITLE' => 'TITLE-' . $i]; + } + + $cnt = 0; + $itemId = []; + foreach ($this->leadService->batch->add($items) as $item) { + $cnt++; + $itemId[] = $item->getId(); + } + + self::assertEquals(count($items), $cnt); + + $cnt = 0; + foreach ($this->leadService->batch->delete($itemId) as $cnt => $deleteResult) { + $cnt++; + } + + self::assertEquals(count($items), $cnt); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + #[\PHPUnit\Framework\Attributes\TestDox('Batch delete leads')] + public function testBatchDelete(): void + { + $leads = []; + for ($i = 1; $i < 60; $i++) { + $leads[] = ['TITLE' => 'TITLE-' . $i]; + } + + $cnt = 0; + $dealId = []; + foreach ($this->leadService->batch->add($leads) as $item) { + $cnt++; + $dealId[] = $item->getId(); + } + + self::assertEquals(count($leads), $cnt); + + $cnt = 0; + foreach ($this->leadService->batch->delete($dealId) as $cnt => $deleteResult) { + $cnt++; + } + + self::assertEquals(count($leads), $cnt); + } + + protected function setUp(): void + { + $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php new file mode 100644 index 00000000..335db892 --- /dev/null +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php @@ -0,0 +1,171 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Company\Service; + + +use Bitrix24\SDK\Services\CRM\Common\ContactConnection; +use Bitrix24\SDK\Services\CRM\Company\Service\CompanyContact; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Builders\Services\CRM\CompanyBuilder; +use Bitrix24\SDK\Tests\Builders\Services\CRM\ContactBuilder; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; +use Bitrix24\SDK\Core; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; + +#[CoversClass(CompanyContact::class)] +#[CoversMethod(CompanyContact::class, 'fields')] +#[CoversMethod(CompanyContact::class, 'setItems')] +#[CoversMethod(CompanyContact::class, 'deleteItems')] +#[CoversMethod(CompanyContact::class, 'get')] +#[CoversMethod(CompanyContact::class, 'add')] +#[CoversMethod(CompanyContact::class, 'delete')] +class CompanyContactTest extends TestCase +{ + use CustomBitrix24Assertions; + + private ServiceBuilder $sb; + + private array $createdCompanies = []; + private array $createdContacts = []; + + public function setUp(): void + { + $this->sb = Fabric::getServiceBuilder(); + } + + public function tearDown(): void + { + foreach ($this->sb->getCRMScope()->company()->batch->delete($this->createdCompanies) as $result) { + } + + foreach ($this->sb->getCRMScope()->contact()->batch->delete($this->createdContacts) as $result) { + } + } + + public function testSet(): void + { + $companyId = $this->sb->getCRMScope()->company()->add((new CompanyBuilder())->build())->getId(); + $this->createdCompanies[] = $companyId; + + $contactIdOne = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); + $this->createdContacts[] = $contactIdOne; + $contactIdTwo = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); + $this->createdContacts[] = $contactIdTwo; + + $this->sb->getCRMScope()->companyContact()->setItems($companyId, [ + new ContactConnection($contactIdOne, 100, true), + new ContactConnection($contactIdTwo, 100, false), + ]); + + $connectedId = [$contactIdOne, $contactIdTwo]; + $connectedContacts = $this->sb->getCRMScope()->companyContact()->get($companyId)->getContactConnections(); + + foreach ($connectedContacts as $item) { + $this->assertContains($item->CONTACT_ID, $connectedId); + } + } + + public function testAdd(): void + { + $companyId = $this->sb->getCRMScope()->company()->add((new CompanyBuilder())->build())->getId(); + $this->createdCompanies[] = $companyId; + + $contactIdOne = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); + $this->createdContacts[] = $contactIdOne; + + $this->assertTrue( + $this->sb->getCRMScope()->companyContact()->add( + $companyId, + new ContactConnection($contactIdOne, 100, true) + )->isSuccess() + ); + + $contactIdTwo = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); + $this->createdContacts[] = $contactIdTwo; + + $this->assertTrue( + $this->sb->getCRMScope()->companyContact()->add( + $companyId, + new ContactConnection($contactIdTwo, 100, true) + )->isSuccess() + ); + + $connectedId = [$contactIdOne, $contactIdTwo]; + $connectedContacts = $this->sb->getCRMScope()->companyContact()->get($companyId)->getContactConnections(); + + foreach ($connectedContacts as $item) { + $this->assertContains($item->CONTACT_ID, $connectedId); + } + } + + public function testDeleteItems(): void + { + $companyId = $this->sb->getCRMScope()->company()->add((new CompanyBuilder())->build())->getId(); + $this->createdCompanies[] = $companyId; + + $contactIdOne = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); + $this->createdContacts[] = $contactIdOne; + $contactIdTwo = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); + $this->createdContacts[] = $contactIdTwo; + + $this->assertTrue( + $this->sb->getCRMScope()->companyContact()->setItems($companyId, [ + new ContactConnection($contactIdOne, 100, true), + new ContactConnection($contactIdTwo, 100, false), + ])->isSuccess() + ); + + $this->assertTrue($this->sb->getCRMScope()->companyContact()->deleteItems($companyId)->isSuccess()); + + $this->assertCount(0, $this->sb->getCRMScope()->companyContact()->get($companyId)->getContactConnections()); + } + + public function testDelete(): void + { + $companyId = $this->sb->getCRMScope()->company()->add((new CompanyBuilder())->build())->getId(); + $this->createdCompanies[] = $companyId; + + $contactIdOne = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); + $this->createdContacts[] = $contactIdOne; + $contactIdTwo = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); + $this->createdContacts[] = $contactIdTwo; + + $this->assertTrue( + $this->sb->getCRMScope()->companyContact()->setItems($companyId, [ + new ContactConnection($contactIdOne, 100, true), + new ContactConnection($contactIdTwo, 100, false), + ])->isSuccess() + ); + + $this->assertTrue($this->sb->getCRMScope()->companyContact()->delete($companyId, $contactIdTwo)->isSuccess()); + + $this->assertCount(1, $this->sb->getCRMScope()->companyContact()->get($companyId)->getContactConnections()); + } + + public function testSetWithEmptyConnections(): void + { + $this->expectException(Core\Exceptions\InvalidArgumentException::class); + $this->sb->getCRMScope()->companyContact()->setItems(1, []); + } + + public function testSetWithWrongType(): void + { + $this->expectException(Core\Exceptions\InvalidArgumentException::class); + /** @phpstan-ignore */ + $this->sb->getCRMScope()->companyContact()->setItems(1, [new \DateTime()]); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteProductRowsTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteProductRowsTest.php new file mode 100644 index 00000000..02963a86 --- /dev/null +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteProductRowsTest.php @@ -0,0 +1,146 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; + +use Money\Currencies\ISOCurrencies; +use Money\Currency; +use Money\Formatter\DecimalMoneyFormatter; +use Money\Money; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Common\Result\DiscountType; +use Bitrix24\SDK\Services\CRM\Lead\Result\LeadProductRowItemResult; +use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Services\CRM\Lead\Service\LeadProductRows; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Bitrix24\SDK\Tests\Integration\Fabric; +use MoneyPHP\Percentage\Percentage; +use PHPUnit\Framework\TestCase; +use Typhoon\Reflection\TyphoonReflector; + +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Lead\Service\LeadProductRows::class)] +class LeadProductRowsTest extends TestCase +{ + private Lead $leadService; + + private LeadProductRows $leadProductRowsService; + + private DecimalMoneyFormatter $decimalMoneyFormatter; + + private TyphoonReflector $typhoonReflector; + + public function testAllSystemPropertiesAnnotated(): void + { + $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + $this->leadProductRowsService->set( + $leadId, + [ + [ + 'PRODUCT_NAME' => sprintf('product name %s', time()), + 'PRICE' => $this->decimalMoneyFormatter->format(new Money(100000, DemoDataGenerator::getCurrency())), + ], + ] + ); + // get response from server with actual keys + $propListFromApi = array_keys($this->leadProductRowsService->get($leadId)->getCoreResponse()->getResponseData()->getResult()['result']['rows'][0]); + // parse keys from phpdoc annotation + $collection = $this->typhoonReflector->reflectClass(LeadProductRowItemResult::class)->properties(); + $propsFromAnnotations = []; + foreach ($collection as $meta) { + if ($meta->isAnnotated() && !$meta->isNative()) { + $propsFromAnnotations[] = $meta->id->name; + } + } + + $this->assertEquals($propListFromApi, $propsFromAnnotations, + sprintf('in phpdocs annotations for class %s cant find fields from actual api response: %s', + LeadProductRowItemResult::class, + implode(', ', array_values(array_diff($propListFromApi, $propsFromAnnotations))) + )); + + $this->leadService->delete($leadId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testSet(): void + { + $leadId = $this->leadService->add(['TITLE' => sprintf('test lead %s', time())])->getId(); + $lead = $this->leadService->get($leadId)->lead(); + $price = new Money(100000, $lead->CURRENCY_ID); + $discount = new Money(50012, $lead->CURRENCY_ID); + $this::assertTrue( + $this->leadProductRowsService->set( + $leadId, + [ + [ + 'PRODUCT_NAME' => sprintf('product name %s', time()), + 'PRICE' => $this->decimalMoneyFormatter->format($price), + 'DISCOUNT_TYPE_ID' => 1, + 'DISCOUNT_SUM' => $this->decimalMoneyFormatter->format($discount) + ], + ] + )->isSuccess() + ); + $leadProductRowItemsResult = $this->leadProductRowsService->get($leadId); + $this->assertCount(1, $leadProductRowItemsResult->getProductRows()); + $productRow = $leadProductRowItemsResult->getProductRows()[0]; + $this->assertEquals($price, $productRow->PRICE); + $this->assertEquals(DiscountType::monetary, $productRow->DISCOUNT_TYPE_ID); + $this->assertEquals($discount, $productRow->DISCOUNT_SUM); + $discount = $discount->multiply(100)->divide($this->decimalMoneyFormatter->format($price->add($discount))); + $calculatedPercentage = new Percentage((string)((int)$discount->getAmount() / 100)); + $this->assertEquals($calculatedPercentage, $productRow->DISCOUNT_RATE); + + $this->leadService->delete($leadId); + } + + public function testGet(): void + { + $leadId = $this->leadService->add(['TITLE' => sprintf('test lead %s', time())])->getId(); + $lead = $this->leadService->get($leadId)->lead(); + $price = new Money(100000, $lead->CURRENCY_ID); + $discount = new Money(0, $lead->CURRENCY_ID); + $this::assertTrue( + $this->leadProductRowsService->set( + $leadId, + [ + [ + 'PRODUCT_NAME' => sprintf('product name %s', time()), + 'PRICE' => $this->decimalMoneyFormatter->format($price), + ], + ] + )->isSuccess() + ); + $leadProductRowItemsResult = $this->leadProductRowsService->get($leadId); + $this->assertCount(1, $leadProductRowItemsResult->getProductRows()); + $productRow = $leadProductRowItemsResult->getProductRows()[0]; + $this->assertEquals($price, $productRow->PRICE); + $this->assertEquals(DiscountType::percentage, $productRow->DISCOUNT_TYPE_ID); + $this->assertEquals($discount, $productRow->DISCOUNT_SUM); + $this->assertEquals(Percentage::zero(), $productRow->DISCOUNT_RATE); + + $this->leadService->delete($leadId); + } + + protected function setUp(): void + { + $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); + $this->leadProductRowsService = Fabric::getServiceBuilder()->getCRMScope()->leadProductRows(); + $this->decimalMoneyFormatter = new DecimalMoneyFormatter(new ISOCurrencies()); + $this->typhoonReflector = TyphoonReflector::build(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteTest.php new file mode 100644 index 00000000..eb020fa0 --- /dev/null +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteTest.php @@ -0,0 +1,154 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core; +use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; +use Bitrix24\SDK\Services\CRM\Lead\Result\LeadItemResult; +use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversFunction; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; + +/** + * Class LeadTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service + */ +#[CoversMethod(Lead::class,'add')] +#[CoversMethod(Lead::class,'delete')] +#[CoversMethod(Lead::class,'get')] +#[CoversMethod(Lead::class,'list')] +#[CoversMethod(Lead::class,'fields')] +#[CoversMethod(Lead::class,'update')] +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Lead\Service\Lead::class)] +class LeadTest extends TestCase +{ + use CustomBitrix24Assertions; + protected Lead $leadService; + + public function testAllSystemFieldsAnnotated(): void + { + $propListFromApi = (new Core\Fields\FieldsFilter())->filterSystemFields(array_keys($this->leadService->fields()->getFieldsDescription())); + $this->assertBitrix24AllResultItemFieldsAnnotated($propListFromApi, LeadItemResult::class); + } + + public function testAllSystemFieldsHasValidTypeAnnotation():void + { + $allFields = $this->leadService->fields()->getFieldsDescription(); + $systemFieldsCodes = (new Core\Fields\FieldsFilter())->filterSystemFields(array_keys($allFields)); + $systemFields = array_filter($allFields, static fn($code): bool => in_array($code, $systemFieldsCodes, true), ARRAY_FILTER_USE_KEY); + + $this->assertBitrix24AllResultItemFieldsHasValidTypeAnnotation( + $systemFields, + LeadItemResult::class); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testAdd(): void + { + self::assertGreaterThan(1, $this->leadService->add(['TITLE' => 'test lead'])->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testDelete(): void + { + self::assertTrue($this->leadService->delete($this->leadService->add(['TITLE' => 'test lead'])->getId())->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + self::assertIsArray($this->leadService->fields()->getFieldsDescription()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGet(): void + { + self::assertGreaterThan( + 1, + $this->leadService->get($this->leadService->add(['TITLE' => 'test Lead'])->getId())->lead()->ID + ); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testList(): void + { + $this->leadService->add(['TITLE' => 'test']); + self::assertGreaterThanOrEqual(1, $this->leadService->list([], [], ['ID', 'TITLE'])->getLeads()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testUpdate(): void + { + $addedItemResult = $this->leadService->add(['TITLE' => 'test lead']); + $newTitle = 'test2'; + + self::assertTrue($this->leadService->update($addedItemResult->getId(), ['TITLE' => $newTitle], [])->isSuccess()); + self::assertEquals($newTitle, $this->leadService->get($addedItemResult->getId())->lead()->TITLE); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testCountByFilter(): void + { + $before = $this->leadService->countByFilter(); + + $newItemsCount = 60; + $items = []; + for ($i = 1; $i <= $newItemsCount; $i++) { + $items[] = ['TITLE' => 'TITLE-' . $i]; + } + + $cnt = 0; + foreach ($this->leadService->batch->add($items) as $item) { + $cnt++; + } + + self::assertEquals(count($items), $cnt); + + $after = $this->leadService->countByFilter(); + + $this->assertEquals($before + $newItemsCount, $after); + } + + protected function setUp(): void + { + $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldTest.php new file mode 100644 index 00000000..29e30fa9 --- /dev/null +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldTest.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; + +use Bitrix24\SDK\Services\CRM\Lead\Service\LeadUserfield; +use Bitrix24\SDK\Tests\Builders\Services\CRM\Userfield\SystemUserfieldBuilder; +use Bitrix24\SDK\Tests\Integration\Fabric; +use Generator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +#[CoversClass(LeadUserfield::class)] +#[CoversMethod(LeadUserfield::class, 'add')] +#[CoversMethod(LeadUserfield::class, 'get')] +#[CoversMethod(LeadUserfield::class, 'list')] +#[CoversMethod(LeadUserfield::class, 'delete')] +#[CoversMethod(LeadUserfield::class, 'update')] +class LeadUserfieldTest extends TestCase +{ + protected LeadUserfield $userfieldService; + + /** + * @throws \Exception + */ + public static function systemUserfieldsDemoDataDataProvider(): Generator + { + yield 'user type id string' => [ + (new SystemUserfieldBuilder())->build(), + ]; + + mt_srand(); + yield 'user type id integer' => [ + (new SystemUserfieldBuilder('integer'))->build(), + ]; + } + + #[DataProvider('systemUserfieldsDemoDataDataProvider')] + public function testAdd(array $newUserFieldItem): void + { + self::assertGreaterThanOrEqual(1, $this->userfieldService->add($newUserFieldItem)->getId()); + } + + #[DataProvider('systemUserfieldsDemoDataDataProvider')] + public function testDelete(array $newUserFieldItem): void + { + $newUserfieldId = $this->userfieldService->add($newUserFieldItem)->getId(); + $this->assertTrue($this->userfieldService->delete($newUserfieldId)->isSuccess()); + } + + #[DataProvider('systemUserfieldsDemoDataDataProvider')] + public function testGet(array $newUserFieldItem): void + { + $newUserfieldId = $this->userfieldService->add($newUserFieldItem)->getId(); + $leadUserfieldItemResult = $this->userfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $leadUserfieldItemResult->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $leadUserfieldItemResult->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $leadUserfieldItemResult->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $leadUserfieldItemResult->XML_ID); + } + + #[DataProvider('systemUserfieldsDemoDataDataProvider')] + public function testUpdate(array $newUserFieldItem): void + { + $newUserfieldId = $this->userfieldService->add($newUserFieldItem)->getId(); + $leadUserfieldItemResult = $this->userfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $leadUserfieldItemResult->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $leadUserfieldItemResult->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $leadUserfieldItemResult->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $leadUserfieldItemResult->XML_ID); + + $this->assertTrue( + $this->userfieldService->update( + $newUserfieldId, + [ + 'EDIT_FORM_LABEL' => $newUserFieldItem['EDIT_FORM_LABEL']['en'] . 'QQQ', + ] + )->isSuccess() + ); + + $ufFieldAfter = $this->userfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($leadUserfieldItemResult->EDIT_FORM_LABEL['en'] . 'QQQ', $ufFieldAfter->EDIT_FORM_LABEL['en']); + } + + public function testList(): void + { + $leadUserfieldsResult = $this->userfieldService->list([], []); + $this->assertGreaterThanOrEqual(0, count($leadUserfieldsResult->getUserfields())); + } + + protected function setUp(): void + { + $this->userfieldService = Fabric::getServiceBuilder()->getCRMScope()->leadUserfield(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldUseCaseTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldUseCaseTest.php new file mode 100644 index 00000000..bfc333c6 --- /dev/null +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldUseCaseTest.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Services\CRM\Lead\Service\LeadUserfield; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Lead\Service\LeadUserfield::class)] +class LeadUserfieldUseCaseTest extends TestCase +{ + protected Lead $leadService; + + protected LeadUserfield $leadUserfieldService; + + protected int $leadUserfieldId; + + /** + * @throws BaseException + * @throws TransportException + */ + public function testOperationsWithUserfieldFromLeadItem(): void + { + // get userfield metadata + $leadUserfieldItemResult = $this->leadUserfieldService->get($this->leadUserfieldId)->userfieldItem(); + $ufOriginalFieldName = $leadUserfieldItemResult->getOriginalFieldName(); + $ufFieldName = $leadUserfieldItemResult->FIELD_NAME; + + // add lead with uf value + $fieldNameValue = 'test field value'; + $newLeadId = $this->leadService->add( + [ + 'TITLE' => 'test lead', + $ufFieldName => $fieldNameValue, + ] + )->getId(); + $lead = $this->leadService->get($newLeadId)->lead(); + $this->assertEquals($fieldNameValue, $lead->getUserfieldByFieldName($ufOriginalFieldName)); + + // update lead userfield value + $newUfValue = 'test 2'; + $this->assertTrue( + $this->leadService->update( + $lead->ID, + [ + $ufFieldName => $newUfValue, + ] + )->isSuccess() + ); + $leadItemResult = $this->leadService->get($lead->ID)->lead(); + $this->assertEquals($newUfValue, $leadItemResult->getUserfieldByFieldName($ufOriginalFieldName)); + } + + /** + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + protected function setUp(): void + { + $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); + $this->leadUserfieldService = Fabric::getServiceBuilder()->getCRMScope()->leadUserfield(); + + $this->leadUserfieldId = $this->leadUserfieldService->add( + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'USER_TYPE_ID' => 'string', + 'XML_ID' => 'b24phpsdk_type_string', + 'SETTINGS' => [ + 'DEFAULT_VALUE' => 'hello world', + ], + ] + )->getId(); + } + + protected function tearDown(): void + { + $this->leadUserfieldService->delete($this->leadUserfieldId); + } +} \ No newline at end of file From 7465bc8e1515cb025a84d0d683349401934410b2 Mon Sep 17 00:00:00 2001 From: Vadim Soluyanov Date: Thu, 19 Jun 2025 16:23:07 +0400 Subject: [PATCH 4/8] add events, modify configs of the linters --- .php-cs-fixer.php | 2 +- CHANGELOG.md | 33 ++++++ Makefile | 6 +- phpstan.neon.dist | 6 +- phpunit.xml.dist | 3 + rector.php | 4 +- src/Services/CRM/CRMServiceBuilder.php | 50 +++++++++ .../Quote/Events/CrmQuoteEventsFactory.php | 68 ++++++++++++ .../OnCrmQuoteUserFieldAdd.php | 27 +++++ .../OnCrmQuoteUserFieldAddPayload.php | 26 +++++ .../OnCrmQuoteUserFieldDelete.php | 26 +++++ .../OnCrmQuoteUserFieldDeletePayload.php | 26 +++++ .../OnCrmQuoteUserFieldSetEnumValues.php | 26 +++++ ...nCrmQuoteUserFieldSetEnumValuesPayload.php | 26 +++++ .../OnCrmQuoteUserFieldUpdate.php | 26 +++++ .../OnCrmQuoteUserFieldUpdatePayload.php | 26 +++++ .../Services/CRM/Quote/Service/BatchTest.php | 56 +++++----- .../CRM/Quote/Service/QuoteContactTest.php | 75 +++++++------ .../Quote/Service/QuoteProductRowsTest.php | 87 +++++++-------- .../Services/CRM/Quote/Service/QuoteTest.php | 77 +++++++------ .../CRM/Quote/Service/QuoteUserfieldTest.php | 57 +++++----- .../Service/QuoteUserfieldUseCaseTest.php | 101 +++++++++--------- 22 files changed, 602 insertions(+), 232 deletions(-) create mode 100644 src/Services/CRM/Quote/Events/CrmQuoteEventsFactory.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAdd.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAddPayload.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDelete.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDeletePayload.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValues.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValuesPayload.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdate.php create mode 100644 src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdatePayload.php diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 98e2153c..d4c18321 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -6,7 +6,7 @@ $finder = Finder::create() ->in(__DIR__ . '/src/Infrastructure/Console/Commands/') - ->in(__DIR__ . '/src/Services/CRM/Deal/') + ->in(__DIR__ . '/src/Services/CRM/Quote/') ->name('*.php') ->exclude(['vendor', 'storage', 'docker', 'docs']) // Exclude directories ->ignoreDotFiles(true) diff --git a/CHANGELOG.md b/CHANGELOG.md index 538644ae..692d2c01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,39 @@ ### Added +- Added service `Services\CRM\Quote\Service\Quote` with support methods, + see [crm.quote.* methods](https://github.com/bitrix24/b24phpsdk/issues/179): + - `fields` returns a list of fields for the quote + - `get` returns the settings of the quote by Id + - `list` returns a list of quote + - `add` creates a new quote + - `delete` deletes a quote + - `update` modifies the quote + - `countByFilter` count quotes by filter +- Added support for events: + - `OnCrmQuoteAdd` + - `OnCrmQuoteDelete` + - `OnCrmQuoteUpdate` + - `OnCrmQuoteUserFieldAdd` + - `OnCrmQuoteUserFieldDelete` + - `OnCrmQuoteUserFieldSetEnumValues` + - `OnCrmQuoteUserFieldUpdate` +- Added service `Services\CRM\Quote\Service\QuoteUserfield` with support methods: + - `add` add userfield to a quote + - `get` get userfield to a quote + - `list` list userfields + - `delete` delete userfield + - `update` update userfield +- Added service `Services\CRM\Quote\Service\QuoteProductRows` with support methods: + - `set` Adds products to a quote + - `get` Returns the products of a quote +- Added service `Services\CRM\Quote\Service\QuoteContact` with support methods, + - `fields` get fiels for quote contact connection + - `setItems` set contacts related with quote + - `get` get contacts related to quote + - `deleteItems` delete all relations for quote + - `add` add contact relation with quote + - `delete` delete contact relation with quote - Added service `Services\CRM\Deal\Service\DealRecurring` with support methods, see [crm.deal.recurring.* methods](https://github.com/bitrix24/b24phpsdk/issues/160): - `fields` returns a list of fields for the recurring deal template diff --git a/Makefile b/Makefile index 54988e90..38e007a5 100644 --- a/Makefile +++ b/Makefile @@ -183,9 +183,9 @@ test-integration-scope-ai-admin: integration_tests_deal_recurring: docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_deal_recurring -.PHONY: integration_tests_scope_automation -integration_tests_scope_automation: - docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_scope_automation +.PHONY: integration_tests_crm_quote +integration_tests_crm_quote: + docker-compose run --rm php-cli vendor/bin/phpunit --testsuite integration_tests_crm_quote # work dev environment .PHONY: php-dev-server-up diff --git a/phpstan.neon.dist b/phpstan.neon.dist index b221d630..2b249d41 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -11,7 +11,11 @@ parameters: - tests/Integration/Services/IMOpenLines - tests/Integration/Services/Main - tests/Integration/Services/Placement - - tests/Integration/Services/CRM/Deal/Service/DealRecurringTest.php + - tests/Integration/Services/CRM/Quote/Service/QuoteTest.php + - tests/Integration/Services/CRM/Quote/Service/BatchTest.php + - tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php + - tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldTest.php + - tests/Integration/Services/CRM/Quote/Service/QuoteProductRowsTest.php bootstrapFiles: - tests/bootstrap.php parallel: diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e96ed8b0..1307b18a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -49,6 +49,9 @@ ./tests/Integration/Services/CRM/Automation/ + + ./tests/Integration/Services/CRM/Quote/ + diff --git a/rector.php b/rector.php index e7039434..cebb52db 100644 --- a/rector.php +++ b/rector.php @@ -36,8 +36,8 @@ __DIR__ . '/tests/Integration/Services/Main', __DIR__ . '/src/Services/Placement', __DIR__ . '/tests/Integration/Services/Placement', - __DIR__ . '/src/Services/CRM/Deal', - __DIR__ . '/tests/Integration/Services/CRM/Deal/Service', + __DIR__ . '/src/Services/CRM/Quote', + __DIR__ . '/tests/Integration/Services/CRM/Quote/Service', __DIR__ . '/tests/Unit/', ]) ->withCache(cacheDirectory: __DIR__ . '.cache/rector') diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index 0ef92763..915f079a 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -277,6 +277,56 @@ public function lead(): Lead\Service\Lead return $this->serviceCache[__METHOD__]; } + + public function quote(): Quote\Service\Quote + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Quote\Service\Quote( + new Quote\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function quoteContact(): Quote\Service\QuoteContact + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Quote\Service\QuoteContact( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return Quote\Service\QuoteProductRows + */ + public function quoteProductRows(): Quote\Service\QuoteProductRows + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Quote\Service\QuoteProductRows($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + public function quoteUserfield(): Quote\Service\QuoteUserfield + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Quote\Service\QuoteUserfield( + new UserfieldConstraints(), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } public function activity(): Activity\Service\Activity { diff --git a/src/Services/CRM/Quote/Events/CrmQuoteEventsFactory.php b/src/Services/CRM/Quote/Events/CrmQuoteEventsFactory.php new file mode 100644 index 00000000..6003ea87 --- /dev/null +++ b/src/Services/CRM/Quote/Events/CrmQuoteEventsFactory.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + + +namespace Bitrix24\SDK\Services\CRM\Quote\Events; + + +use Bitrix24\SDK\Core\Contracts\Events\EventInterface; +use Bitrix24\SDK\Core\Contracts\Events\EventsFabricInterface; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteAdd\OnCrmQuoteAdd; +use Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteDelete\OnCrmQuoteDelete; +use Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUpdate\OnCrmQuoteUpdate; +use Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldAdd\OnCrmQuoteUserFieldAdd; +use Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldDelete\OnCrmQuoteUserFieldDelete; +use Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldSetEnumValues\OnCrmQuoteUserFieldSetEnumValues; +use Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldUpdate\OnCrmQuoteUserFieldUpdate; +use Symfony\Component\HttpFoundation\Request; + +readonly class CrmQuoteEventsFactory implements EventsFabricInterface +{ + public function isSupport(string $eventCode): bool + { + return in_array(strtoupper($eventCode), [ + OnCrmQuoteAdd::CODE, + OnCrmQuoteUpdate::CODE, + OnCrmQuoteDelete::CODE, + OnCrmQuoteUserFieldAdd::CODE, + OnCrmQuoteUserFieldUpdate::CODE, + OnCrmQuoteUserFieldDelete::CODE, + OnCrmQuoteUserFieldSetEnumValues::CODE, + ], true); + } + + /** + * @throws InvalidArgumentException + */ + public function create(Request $eventRequest): EventInterface + { + $eventPayload = $eventRequest->request->all(); + if (!array_key_exists('event', $eventPayload)) { + throw new InvalidArgumentException('«event» key not found in event payload'); + } + + return match ($eventPayload['event']) { + OnCrmQuoteAdd::CODE => new OnCrmQuoteAdd($eventRequest), + OnCrmQuoteUpdate::CODE => new OnCrmQuoteUpdate($eventRequest), + OnCrmQuoteDelete::CODE => new OnCrmQuoteDelete($eventRequest), + OnCrmQuoteUserFieldAdd::CODE => new OnCrmQuoteUserFieldAdd($eventRequest), + OnCrmQuoteUserFieldUpdate::CODE => new OnCrmQuoteUserFieldUpdate($eventRequest), + OnCrmQuoteUserFieldDelete::CODE => new OnCrmQuoteUserFieldDelete($eventRequest), + OnCrmQuoteUserFieldSetEnumValues::CODE => new OnCrmQuoteUserFieldSetEnumValues($eventRequest), + default => throw new InvalidArgumentException( + sprintf('Unexpected event code «%s»', $eventPayload['event']) + ), + }; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAdd.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAdd.php new file mode 100644 index 00000000..c14e21d3 --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAdd.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldAdd; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; +use Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteAdd\OnCrmQuoteUserFieldAddPayload; + +class OnCrmQuoteUserFieldAdd extends AbstractEventRequest +{ + public const CODE = 'ONCRMQUOTEUSERFIELDADD'; + + public function getPayload(): OnCrmQuoteUserFieldAddPayload + { + return new OnCrmQuoteUserFieldAddPayload($this->eventPayload['data']); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAddPayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAddPayload.php new file mode 100644 index 00000000..ce44b3f8 --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAddPayload.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldAdd; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; + +/** + * @property-read positive-int $id + * @property-read non-empty-string $entityId + * @property-read non-empty-string $fieldName + */ +class OnCrmQuoteUserFieldAddPayload extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDelete.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDelete.php new file mode 100644 index 00000000..95b3a3ed --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDelete.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldDelete; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnCrmQuoteUserFieldDelete extends AbstractEventRequest +{ + public const CODE = 'ONCRMQUOTEUSERFIELDDELETE'; + + public function getPayload(): OnCrmQuoteUserFieldDeletePayload + { + return new OnCrmQuoteUserFieldDeletePayload($this->eventPayload['data']); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDeletePayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDeletePayload.php new file mode 100644 index 00000000..e01d39fb --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDeletePayload.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldDelete; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; + +/** + * @property-read positive-int $id + * @property-read non-empty-string $entityId + * @property-read non-empty-string $fieldName + */ +class OnCrmQuoteUserFieldDeletePayload extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValues.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValues.php new file mode 100644 index 00000000..d67a3cd9 --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValues.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldSetEnumValues; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnCrmQuoteUserFieldSetEnumValues extends AbstractEventRequest +{ + public const CODE = 'ONCRMQUOTEUSERFIELDSETENUMVALUES'; + + public function getPayload(): OnCrmQuoteUserFieldSetEnumValuesPayload + { + return new OnCrmQuoteUserFieldSetEnumValuesPayload($this->eventPayload['data']); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValuesPayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValuesPayload.php new file mode 100644 index 00000000..8390e369 --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValuesPayload.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldSetEnumValues; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; + +/** + * @property-read positive-int $id + * @property-read non-empty-string $entityId + * @property-read non-empty-string $fieldName + */ +class OnCrmQuoteUserFieldSetEnumValuesPayload extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdate.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdate.php new file mode 100644 index 00000000..940b84ba --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdate.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldUpdate; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnCrmQuoteUserFieldUpdate extends AbstractEventRequest +{ + public const CODE = 'ONCRMQUOTEUSERFIELDUPDATE'; + + public function getPayload(): OnCrmQuoteUserFieldUpdatePayload + { + return new OnCrmQuoteUserFieldUpdatePayload($this->eventPayload['data']); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdatePayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdatePayload.php new file mode 100644 index 00000000..4c24465c --- /dev/null +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdatePayload.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldUpdate; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; + +/** + * @property-read positive-int $id + * @property-read non-empty-string $entityId + * @property-read non-empty-string $fieldName + */ +class OnCrmQuoteUserFieldUpdatePayload extends AbstractItem +{ +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Quote/Service/BatchTest.php b/tests/Integration/Services/CRM/Quote/Service/BatchTest.php index c4404010..c18ac093 100644 --- a/tests/Integration/Services/CRM/Quote/Service/BatchTest.php +++ b/tests/Integration/Services/CRM/Quote/Service/BatchTest.php @@ -3,7 +3,7 @@ /** * This file is part of the bitrix24-php-sdk package. * - * © Maksim Mesilov + * © Vadim Soluyanov * * For the full copyright and license information, please view the MIT-LICENSE.txt * file that was distributed with this source code. @@ -11,47 +11,53 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Quote\Service; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; -use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Services\CRM\Quote\Service\Quote; use Bitrix24\SDK\Tests\Integration\Fabric; use PHPUnit\Framework\TestCase; /** * Class BatchTest * - * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Quote\Service */ -#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Lead\Service\Batch::class)] +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Quote\Service\Batch::class)] class BatchTest extends TestCase { - protected Lead $leadService; + protected Quote $quoteService; + + + protected function setUp(): void + { + $this->quoteService = Fabric::getServiceBuilder()->getCRMScope()->quote(); + } /** * @throws BaseException * @throws TransportException */ - #[\PHPUnit\Framework\Attributes\TestDox('Batch list leads')] + #[\PHPUnit\Framework\Attributes\TestDox('Batch list quotes')] public function testBatchList(): void { - $itemId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); + $itemId = $this->quoteService->add(['TITLE' => 'test quote'])->getId(); $cnt = 0; - foreach ($this->leadService->batch->list([], ['ID' => $itemId], ['ID', 'NAME'], 1) as $item) { + foreach ($this->quoteService->batch->list([], ['ID' => $itemId], ['ID', 'NAME'], 1) as $item) { $cnt++; } self::assertGreaterThanOrEqual(1, $cnt); - $this->leadService->delete($itemId); + $this->quoteService->delete($itemId); } /** * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - #[\PHPUnit\Framework\Attributes\TestDox('Batch add lead')] + #[\PHPUnit\Framework\Attributes\TestDox('Batch add quote')] public function testBatchAdd(): void { $items = []; @@ -61,7 +67,7 @@ public function testBatchAdd(): void $cnt = 0; $itemId = []; - foreach ($this->leadService->batch->add($items) as $item) { + foreach ($this->quoteService->batch->add($items) as $item) { $cnt++; $itemId[] = $item->getId(); } @@ -69,7 +75,7 @@ public function testBatchAdd(): void self::assertEquals(count($items), $cnt); $cnt = 0; - foreach ($this->leadService->batch->delete($itemId) as $cnt => $deleteResult) { + foreach ($this->quoteService->batch->delete($itemId) as $cnt => $deleteResult) { $cnt++; } @@ -79,33 +85,29 @@ public function testBatchAdd(): void /** * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ - #[\PHPUnit\Framework\Attributes\TestDox('Batch delete leads')] + #[\PHPUnit\Framework\Attributes\TestDox('Batch delete quotes')] public function testBatchDelete(): void { - $leads = []; + $quotes = []; for ($i = 1; $i < 60; $i++) { - $leads[] = ['TITLE' => 'TITLE-' . $i]; + $quotes[] = ['TITLE' => 'TITLE-' . $i]; } $cnt = 0; - $dealId = []; - foreach ($this->leadService->batch->add($leads) as $item) { + $itemId = []; + foreach ($this->quoteService->batch->add($quotes) as $item) { $cnt++; - $dealId[] = $item->getId(); + $itemId[] = $item->getId(); } - self::assertEquals(count($leads), $cnt); + self::assertEquals(count($quotes), $cnt); $cnt = 0; - foreach ($this->leadService->batch->delete($dealId) as $cnt => $deleteResult) { + foreach ($this->quoteService->batch->delete($itemId) as $cnt => $deleteResult) { $cnt++; } - self::assertEquals(count($leads), $cnt); + self::assertEquals(count($quotes), $cnt); } - protected function setUp(): void - { - $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); - } -} \ No newline at end of file +} diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php index 335db892..2c9aee9f 100644 --- a/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php @@ -3,7 +3,7 @@ /** * This file is part of the bitrix24-php-sdk package. * - * © Maksim Mesilov + * © Vadim Soluyanov * * For the full copyright and license information, please view the MIT-LICENSE.txt * file that was distributed with this source code. @@ -11,13 +11,12 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Company\Service; +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Quote\Service; use Bitrix24\SDK\Services\CRM\Common\ContactConnection; -use Bitrix24\SDK\Services\CRM\Company\Service\CompanyContact; +use Bitrix24\SDK\Services\CRM\Quote\Service\QuoteContact; use Bitrix24\SDK\Services\ServiceBuilder; -use Bitrix24\SDK\Tests\Builders\Services\CRM\CompanyBuilder; use Bitrix24\SDK\Tests\Builders\Services\CRM\ContactBuilder; use Bitrix24\SDK\Tests\Integration\Fabric; use PHPUnit\Framework\Attributes\CoversClass; @@ -26,20 +25,20 @@ use Bitrix24\SDK\Core; use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; -#[CoversClass(CompanyContact::class)] -#[CoversMethod(CompanyContact::class, 'fields')] -#[CoversMethod(CompanyContact::class, 'setItems')] -#[CoversMethod(CompanyContact::class, 'deleteItems')] -#[CoversMethod(CompanyContact::class, 'get')] -#[CoversMethod(CompanyContact::class, 'add')] -#[CoversMethod(CompanyContact::class, 'delete')] -class CompanyContactTest extends TestCase +#[CoversClass(QuoteContact::class)] +#[CoversMethod(QuoteContact::class, 'fields')] +#[CoversMethod(QuoteContact::class, 'setItems')] +#[CoversMethod(QuoteContact::class, 'deleteItems')] +#[CoversMethod(QuoteContact::class, 'get')] +#[CoversMethod(QuoteContact::class, 'add')] +#[CoversMethod(QuoteContact::class, 'delete')] +class QuoteContactTest extends TestCase { use CustomBitrix24Assertions; private ServiceBuilder $sb; - private array $createdCompanies = []; + private array $createdQuotes = []; private array $createdContacts = []; public function setUp(): void @@ -49,7 +48,7 @@ public function setUp(): void public function tearDown(): void { - foreach ($this->sb->getCRMScope()->company()->batch->delete($this->createdCompanies) as $result) { + foreach ($this->sb->getCRMScope()->quote()->batch->delete($this->createdQuotes) as $result) { } foreach ($this->sb->getCRMScope()->contact()->batch->delete($this->createdContacts) as $result) { @@ -58,21 +57,21 @@ public function tearDown(): void public function testSet(): void { - $companyId = $this->sb->getCRMScope()->company()->add((new CompanyBuilder())->build())->getId(); - $this->createdCompanies[] = $companyId; + $quoteId = $this->sb->getCRMScope()->quote()->add(['TITLE' => 'test quote'])->getId(); + $this->createdQuotes[] = $quoteId; $contactIdOne = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); $this->createdContacts[] = $contactIdOne; $contactIdTwo = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); $this->createdContacts[] = $contactIdTwo; - $this->sb->getCRMScope()->companyContact()->setItems($companyId, [ + $this->sb->getCRMScope()->quoteContact()->setItems($quoteId, [ new ContactConnection($contactIdOne, 100, true), new ContactConnection($contactIdTwo, 100, false), ]); $connectedId = [$contactIdOne, $contactIdTwo]; - $connectedContacts = $this->sb->getCRMScope()->companyContact()->get($companyId)->getContactConnections(); + $connectedContacts = $this->sb->getCRMScope()->quoteContact()->get($quoteId)->getContactConnections(); foreach ($connectedContacts as $item) { $this->assertContains($item->CONTACT_ID, $connectedId); @@ -81,15 +80,15 @@ public function testSet(): void public function testAdd(): void { - $companyId = $this->sb->getCRMScope()->company()->add((new CompanyBuilder())->build())->getId(); - $this->createdCompanies[] = $companyId; + $quoteId = $this->sb->getCRMScope()->quote()->add(['TITLE' => 'test quote'])->getId(); + $this->createdQuotes[] = $quoteId; $contactIdOne = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); $this->createdContacts[] = $contactIdOne; $this->assertTrue( - $this->sb->getCRMScope()->companyContact()->add( - $companyId, + $this->sb->getCRMScope()->quoteContact()->add( + $quoteId, new ContactConnection($contactIdOne, 100, true) )->isSuccess() ); @@ -98,14 +97,14 @@ public function testAdd(): void $this->createdContacts[] = $contactIdTwo; $this->assertTrue( - $this->sb->getCRMScope()->companyContact()->add( - $companyId, + $this->sb->getCRMScope()->quoteContact()->add( + $quoteId, new ContactConnection($contactIdTwo, 100, true) )->isSuccess() ); $connectedId = [$contactIdOne, $contactIdTwo]; - $connectedContacts = $this->sb->getCRMScope()->companyContact()->get($companyId)->getContactConnections(); + $connectedContacts = $this->sb->getCRMScope()->quoteContact()->get($quoteId)->getContactConnections(); foreach ($connectedContacts as $item) { $this->assertContains($item->CONTACT_ID, $connectedId); @@ -114,8 +113,8 @@ public function testAdd(): void public function testDeleteItems(): void { - $companyId = $this->sb->getCRMScope()->company()->add((new CompanyBuilder())->build())->getId(); - $this->createdCompanies[] = $companyId; + $quoteId = $this->sb->getCRMScope()->quote()->add(['TITLE' => 'test quote'])->getId(); + $this->createdQuotes[] = $quoteId; $contactIdOne = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); $this->createdContacts[] = $contactIdOne; @@ -123,21 +122,21 @@ public function testDeleteItems(): void $this->createdContacts[] = $contactIdTwo; $this->assertTrue( - $this->sb->getCRMScope()->companyContact()->setItems($companyId, [ + $this->sb->getCRMScope()->quoteContact()->setItems($quoteId, [ new ContactConnection($contactIdOne, 100, true), new ContactConnection($contactIdTwo, 100, false), ])->isSuccess() ); - $this->assertTrue($this->sb->getCRMScope()->companyContact()->deleteItems($companyId)->isSuccess()); + $this->assertTrue($this->sb->getCRMScope()->quoteContact()->deleteItems($quoteId)->isSuccess()); - $this->assertCount(0, $this->sb->getCRMScope()->companyContact()->get($companyId)->getContactConnections()); + $this->assertCount(0, $this->sb->getCRMScope()->quoteContact()->get($quoteId)->getContactConnections()); } public function testDelete(): void { - $companyId = $this->sb->getCRMScope()->company()->add((new CompanyBuilder())->build())->getId(); - $this->createdCompanies[] = $companyId; + $quoteId = $this->sb->getCRMScope()->quote()->add(['TITLE' => 'test quote'])->getId(); + $this->createdQuotes[] = $quoteId; $contactIdOne = $this->sb->getCRMScope()->contact()->add((new ContactBuilder())->build())->getId(); $this->createdContacts[] = $contactIdOne; @@ -145,27 +144,27 @@ public function testDelete(): void $this->createdContacts[] = $contactIdTwo; $this->assertTrue( - $this->sb->getCRMScope()->companyContact()->setItems($companyId, [ + $this->sb->getCRMScope()->quoteContact()->setItems($quoteId, [ new ContactConnection($contactIdOne, 100, true), new ContactConnection($contactIdTwo, 100, false), ])->isSuccess() ); - $this->assertTrue($this->sb->getCRMScope()->companyContact()->delete($companyId, $contactIdTwo)->isSuccess()); + $this->assertTrue($this->sb->getCRMScope()->quoteContact()->delete($quoteId, $contactIdTwo)->isSuccess()); - $this->assertCount(1, $this->sb->getCRMScope()->companyContact()->get($companyId)->getContactConnections()); + $this->assertCount(1, $this->sb->getCRMScope()->quoteContact()->get($quoteId)->getContactConnections()); } public function testSetWithEmptyConnections(): void { $this->expectException(Core\Exceptions\InvalidArgumentException::class); - $this->sb->getCRMScope()->companyContact()->setItems(1, []); + $this->sb->getCRMScope()->quoteContact()->setItems(1, []); } public function testSetWithWrongType(): void { $this->expectException(Core\Exceptions\InvalidArgumentException::class); - /** @phpstan-ignore */ - $this->sb->getCRMScope()->companyContact()->setItems(1, [new \DateTime()]); + /** @phpstan-ignore-next-line */ + $this->sb->getCRMScope()->quoteContact()->setItems(1, [new \DateTime()]); } } \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteProductRowsTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteProductRowsTest.php index 02963a86..b31217fb 100644 --- a/tests/Integration/Services/CRM/Quote/Service/QuoteProductRowsTest.php +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteProductRowsTest.php @@ -11,7 +11,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Quote\Service; use Money\Currencies\ISOCurrencies; use Money\Currency; @@ -20,31 +20,39 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Services\CRM\Common\Result\DiscountType; -use Bitrix24\SDK\Services\CRM\Lead\Result\LeadProductRowItemResult; -use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; -use Bitrix24\SDK\Services\CRM\Lead\Service\LeadProductRows; +use Bitrix24\SDK\Services\CRM\Quote\Result\QuoteProductRowItemResult; +use Bitrix24\SDK\Services\CRM\Quote\Service\Quote; +use Bitrix24\SDK\Services\CRM\Quote\Service\QuoteProductRows; use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; use Bitrix24\SDK\Tests\Integration\Fabric; use MoneyPHP\Percentage\Percentage; use PHPUnit\Framework\TestCase; use Typhoon\Reflection\TyphoonReflector; -#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Lead\Service\LeadProductRows::class)] -class LeadProductRowsTest extends TestCase +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Quote\Service\QuoteProductRows::class)] +class QuoteProductRowsTest extends TestCase { - private Lead $leadService; + private Quote $quoteService; - private LeadProductRows $leadProductRowsService; + private QuoteProductRows $quoteProductRowsService; private DecimalMoneyFormatter $decimalMoneyFormatter; private TyphoonReflector $typhoonReflector; + + protected function setUp(): void + { + $this->quoteService = Fabric::getServiceBuilder()->getCRMScope()->quote(); + $this->quoteProductRowsService = Fabric::getServiceBuilder()->getCRMScope()->quoteProductRows(); + $this->decimalMoneyFormatter = new DecimalMoneyFormatter(new ISOCurrencies()); + $this->typhoonReflector = TyphoonReflector::build(); + } public function testAllSystemPropertiesAnnotated(): void { - $leadId = $this->leadService->add(['TITLE' => 'test lead'])->getId(); - $this->leadProductRowsService->set( - $leadId, + $quoteId = $this->quoteService->add(['TITLE' => 'test quote'])->getId(); + $this->quoteProductRowsService->set( + $quoteId, [ [ 'PRODUCT_NAME' => sprintf('product name %s', time()), @@ -53,9 +61,9 @@ public function testAllSystemPropertiesAnnotated(): void ] ); // get response from server with actual keys - $propListFromApi = array_keys($this->leadProductRowsService->get($leadId)->getCoreResponse()->getResponseData()->getResult()['result']['rows'][0]); + $propListFromApi = array_keys($this->quoteProductRowsService->get($quoteId)->getCoreResponse()->getResponseData()->getResult()['result']['rows'][0]); // parse keys from phpdoc annotation - $collection = $this->typhoonReflector->reflectClass(LeadProductRowItemResult::class)->properties(); + $collection = $this->typhoonReflector->reflectClass(QuoteProductRowItemResult::class)->properties(); $propsFromAnnotations = []; foreach ($collection as $meta) { if ($meta->isAnnotated() && !$meta->isNative()) { @@ -65,11 +73,11 @@ public function testAllSystemPropertiesAnnotated(): void $this->assertEquals($propListFromApi, $propsFromAnnotations, sprintf('in phpdocs annotations for class %s cant find fields from actual api response: %s', - LeadProductRowItemResult::class, + QuoteProductRowItemResult::class, implode(', ', array_values(array_diff($propListFromApi, $propsFromAnnotations))) )); - $this->leadService->delete($leadId); + $this->quoteService->delete($quoteId); } /** @@ -78,13 +86,13 @@ public function testAllSystemPropertiesAnnotated(): void */ public function testSet(): void { - $leadId = $this->leadService->add(['TITLE' => sprintf('test lead %s', time())])->getId(); - $lead = $this->leadService->get($leadId)->lead(); - $price = new Money(100000, $lead->CURRENCY_ID); - $discount = new Money(50012, $lead->CURRENCY_ID); + $quoteId = $this->quoteService->add(['TITLE' => sprintf('test quote %s', time())])->getId(); + $quote = $this->quoteService->get($quoteId)->quote(); + $price = new Money(100000, $quote->CURRENCY_ID); + $discount = new Money(50012, $quote->CURRENCY_ID); $this::assertTrue( - $this->leadProductRowsService->set( - $leadId, + $this->quoteProductRowsService->set( + $quoteId, [ [ 'PRODUCT_NAME' => sprintf('product name %s', time()), @@ -95,9 +103,9 @@ public function testSet(): void ] )->isSuccess() ); - $leadProductRowItemsResult = $this->leadProductRowsService->get($leadId); - $this->assertCount(1, $leadProductRowItemsResult->getProductRows()); - $productRow = $leadProductRowItemsResult->getProductRows()[0]; + $quoteProductRowItemsResult = $this->quoteProductRowsService->get($quoteId); + $this->assertCount(1, $quoteProductRowItemsResult->getProductRows()); + $productRow = $quoteProductRowItemsResult->getProductRows()[0]; $this->assertEquals($price, $productRow->PRICE); $this->assertEquals(DiscountType::monetary, $productRow->DISCOUNT_TYPE_ID); $this->assertEquals($discount, $productRow->DISCOUNT_SUM); @@ -105,18 +113,18 @@ public function testSet(): void $calculatedPercentage = new Percentage((string)((int)$discount->getAmount() / 100)); $this->assertEquals($calculatedPercentage, $productRow->DISCOUNT_RATE); - $this->leadService->delete($leadId); + $this->quoteService->delete($quoteId); } public function testGet(): void { - $leadId = $this->leadService->add(['TITLE' => sprintf('test lead %s', time())])->getId(); - $lead = $this->leadService->get($leadId)->lead(); - $price = new Money(100000, $lead->CURRENCY_ID); - $discount = new Money(0, $lead->CURRENCY_ID); + $quoteId = $this->quoteService->add(['TITLE' => sprintf('test quote %s', time())])->getId(); + $quote = $this->quoteService->get($quoteId)->quote(); + $price = new Money(100000, $quote->CURRENCY_ID); + $discount = new Money(0, $quote->CURRENCY_ID); $this::assertTrue( - $this->leadProductRowsService->set( - $leadId, + $this->quoteProductRowsService->set( + $quoteId, [ [ 'PRODUCT_NAME' => sprintf('product name %s', time()), @@ -125,22 +133,15 @@ public function testGet(): void ] )->isSuccess() ); - $leadProductRowItemsResult = $this->leadProductRowsService->get($leadId); - $this->assertCount(1, $leadProductRowItemsResult->getProductRows()); - $productRow = $leadProductRowItemsResult->getProductRows()[0]; + $quoteProductRowItemsResult = $this->quoteProductRowsService->get($quoteId); + $this->assertCount(1, $quoteProductRowItemsResult->getProductRows()); + $productRow = $quoteProductRowItemsResult->getProductRows()[0]; $this->assertEquals($price, $productRow->PRICE); $this->assertEquals(DiscountType::percentage, $productRow->DISCOUNT_TYPE_ID); $this->assertEquals($discount, $productRow->DISCOUNT_SUM); $this->assertEquals(Percentage::zero(), $productRow->DISCOUNT_RATE); - $this->leadService->delete($leadId); + $this->quoteService->delete($quoteId); } - protected function setUp(): void - { - $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); - $this->leadProductRowsService = Fabric::getServiceBuilder()->getCRMScope()->leadProductRows(); - $this->decimalMoneyFormatter = new DecimalMoneyFormatter(new ISOCurrencies()); - $this->typhoonReflector = TyphoonReflector::build(); - } -} \ No newline at end of file +} diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteTest.php index eb020fa0..1d851006 100644 --- a/tests/Integration/Services/CRM/Quote/Service/QuoteTest.php +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteTest.php @@ -3,7 +3,7 @@ /** * This file is part of the bitrix24-php-sdk package. * - * © Maksim Mesilov + * © Vadim Soluyanov * * For the full copyright and license information, please view the MIT-LICENSE.txt * file that was distributed with this source code. @@ -11,14 +11,13 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Quote\Service; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Core; -use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; -use Bitrix24\SDK\Services\CRM\Lead\Result\LeadItemResult; -use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Services\CRM\Quote\Result\QuoteItemResult; +use Bitrix24\SDK\Services\CRM\Quote\Service\Quote; use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; use Bitrix24\SDK\Tests\Integration\Fabric; use PHPUnit\Framework\Attributes\CoversFunction; @@ -26,37 +25,42 @@ use PHPUnit\Framework\TestCase; /** - * Class LeadTest + * Class QuoteTest * - * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Quote\Service */ -#[CoversMethod(Lead::class,'add')] -#[CoversMethod(Lead::class,'delete')] -#[CoversMethod(Lead::class,'get')] -#[CoversMethod(Lead::class,'list')] -#[CoversMethod(Lead::class,'fields')] -#[CoversMethod(Lead::class,'update')] -#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Lead\Service\Lead::class)] -class LeadTest extends TestCase +#[CoversMethod(Quote::class,'add')] +#[CoversMethod(Quote::class,'delete')] +#[CoversMethod(Quote::class,'get')] +#[CoversMethod(Quote::class,'list')] +#[CoversMethod(Quote::class,'fields')] +#[CoversMethod(Quote::class,'update')] +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Quote\Service\Quote::class)] +class QuoteTest extends TestCase { use CustomBitrix24Assertions; - protected Lead $leadService; + protected Quote $quoteService; + + protected function setUp(): void + { + $this->quoteService = Fabric::getServiceBuilder()->getCRMScope()->quote(); + } public function testAllSystemFieldsAnnotated(): void { - $propListFromApi = (new Core\Fields\FieldsFilter())->filterSystemFields(array_keys($this->leadService->fields()->getFieldsDescription())); - $this->assertBitrix24AllResultItemFieldsAnnotated($propListFromApi, LeadItemResult::class); + $propListFromApi = (new Core\Fields\FieldsFilter())->filterSystemFields(array_keys($this->quoteService->fields()->getFieldsDescription())); + $this->assertBitrix24AllResultItemFieldsAnnotated($propListFromApi, QuoteItemResult::class); } public function testAllSystemFieldsHasValidTypeAnnotation():void { - $allFields = $this->leadService->fields()->getFieldsDescription(); + $allFields = $this->quoteService->fields()->getFieldsDescription(); $systemFieldsCodes = (new Core\Fields\FieldsFilter())->filterSystemFields(array_keys($allFields)); $systemFields = array_filter($allFields, static fn($code): bool => in_array($code, $systemFieldsCodes, true), ARRAY_FILTER_USE_KEY); $this->assertBitrix24AllResultItemFieldsHasValidTypeAnnotation( $systemFields, - LeadItemResult::class); + QuoteItemResult::class); } /** @@ -65,7 +69,7 @@ public function testAllSystemFieldsHasValidTypeAnnotation():void */ public function testAdd(): void { - self::assertGreaterThan(1, $this->leadService->add(['TITLE' => 'test lead'])->getId()); + self::assertGreaterThan(1, $this->quoteService->add(['TITLE' => 'test quote'])->getId()); } /** @@ -74,7 +78,7 @@ public function testAdd(): void */ public function testDelete(): void { - self::assertTrue($this->leadService->delete($this->leadService->add(['TITLE' => 'test lead'])->getId())->isSuccess()); + self::assertTrue($this->quoteService->delete($this->quoteService->add(['TITLE' => 'test quote 1'])->getId())->isSuccess()); } /** @@ -83,7 +87,7 @@ public function testDelete(): void */ public function testFields(): void { - self::assertIsArray($this->leadService->fields()->getFieldsDescription()); + self::assertIsArray($this->quoteService->fields()->getFieldsDescription()); } /** @@ -94,7 +98,7 @@ public function testGet(): void { self::assertGreaterThan( 1, - $this->leadService->get($this->leadService->add(['TITLE' => 'test Lead'])->getId())->lead()->ID + $this->quoteService->get($this->quoteService->add(['TITLE' => 'test Quote 2'])->getId())->quote()->ID ); } @@ -104,8 +108,8 @@ public function testGet(): void */ public function testList(): void { - $this->leadService->add(['TITLE' => 'test']); - self::assertGreaterThanOrEqual(1, $this->leadService->list([], [], ['ID', 'TITLE'])->getLeads()); + $this->quoteService->add(['TITLE' => 'test']); + self::assertGreaterThanOrEqual(1, $this->quoteService->list([], [], ['ID', 'TITLE'])->getQuotes()); } /** @@ -114,11 +118,11 @@ public function testList(): void */ public function testUpdate(): void { - $addedItemResult = $this->leadService->add(['TITLE' => 'test lead']); + $addedItemResult = $this->quoteService->add(['TITLE' => 'test quote']); $newTitle = 'test2'; - self::assertTrue($this->leadService->update($addedItemResult->getId(), ['TITLE' => $newTitle], [])->isSuccess()); - self::assertEquals($newTitle, $this->leadService->get($addedItemResult->getId())->lead()->TITLE); + self::assertTrue($this->quoteService->update($addedItemResult->getId(), ['TITLE' => $newTitle], [])->isSuccess()); + self::assertEquals($newTitle, $this->quoteService->get($addedItemResult->getId())->quote()->TITLE); } /** @@ -127,28 +131,23 @@ public function testUpdate(): void */ public function testCountByFilter(): void { - $before = $this->leadService->countByFilter(); + $before = $this->quoteService->countByFilter(); - $newItemsCount = 60; + $newItemsCount = 20; $items = []; for ($i = 1; $i <= $newItemsCount; $i++) { $items[] = ['TITLE' => 'TITLE-' . $i]; } $cnt = 0; - foreach ($this->leadService->batch->add($items) as $item) { + foreach ($this->quoteService->batch->add($items) as $item) { $cnt++; } self::assertEquals(count($items), $cnt); - $after = $this->leadService->countByFilter(); + $after = $this->quoteService->countByFilter(); $this->assertEquals($before + $newItemsCount, $after); } - - protected function setUp(): void - { - $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); - } -} \ No newline at end of file +} diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldTest.php index 29e30fa9..78a16023 100644 --- a/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldTest.php +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldTest.php @@ -11,9 +11,9 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Quote\Service; -use Bitrix24\SDK\Services\CRM\Lead\Service\LeadUserfield; +use Bitrix24\SDK\Services\CRM\Quote\Service\QuoteUserfield; use Bitrix24\SDK\Tests\Builders\Services\CRM\Userfield\SystemUserfieldBuilder; use Bitrix24\SDK\Tests\Integration\Fabric; use Generator; @@ -22,15 +22,20 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; -#[CoversClass(LeadUserfield::class)] -#[CoversMethod(LeadUserfield::class, 'add')] -#[CoversMethod(LeadUserfield::class, 'get')] -#[CoversMethod(LeadUserfield::class, 'list')] -#[CoversMethod(LeadUserfield::class, 'delete')] -#[CoversMethod(LeadUserfield::class, 'update')] -class LeadUserfieldTest extends TestCase +#[CoversClass(QuoteUserfield::class)] +#[CoversMethod(QuoteUserfield::class, 'add')] +#[CoversMethod(QuoteUserfield::class, 'get')] +#[CoversMethod(QuoteUserfield::class, 'list')] +#[CoversMethod(QuoteUserfield::class, 'delete')] +#[CoversMethod(QuoteUserfield::class, 'update')] +class QuoteUserfieldTest extends TestCase { - protected LeadUserfield $userfieldService; + protected QuoteUserfield $userfieldService; + + protected function setUp(): void + { + $this->userfieldService = Fabric::getServiceBuilder()->getCRMScope()->quoteUserfield(); + } /** * @throws \Exception @@ -64,22 +69,22 @@ public function testDelete(array $newUserFieldItem): void public function testGet(array $newUserFieldItem): void { $newUserfieldId = $this->userfieldService->add($newUserFieldItem)->getId(); - $leadUserfieldItemResult = $this->userfieldService->get($newUserfieldId)->userfieldItem(); - $this->assertEquals($newUserfieldId, $leadUserfieldItemResult->ID); - $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $leadUserfieldItemResult->USER_TYPE_ID); - $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $leadUserfieldItemResult->FIELD_NAME); - $this->assertEquals($newUserFieldItem['XML_ID'], $leadUserfieldItemResult->XML_ID); + $quoteUserfieldItemResult = $this->userfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $quoteUserfieldItemResult->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $quoteUserfieldItemResult->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $quoteUserfieldItemResult->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $quoteUserfieldItemResult->XML_ID); } #[DataProvider('systemUserfieldsDemoDataDataProvider')] public function testUpdate(array $newUserFieldItem): void { $newUserfieldId = $this->userfieldService->add($newUserFieldItem)->getId(); - $leadUserfieldItemResult = $this->userfieldService->get($newUserfieldId)->userfieldItem(); - $this->assertEquals($newUserfieldId, $leadUserfieldItemResult->ID); - $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $leadUserfieldItemResult->USER_TYPE_ID); - $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $leadUserfieldItemResult->FIELD_NAME); - $this->assertEquals($newUserFieldItem['XML_ID'], $leadUserfieldItemResult->XML_ID); + $quoteUserfieldItemResult = $this->userfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $quoteUserfieldItemResult->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $quoteUserfieldItemResult->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $quoteUserfieldItemResult->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $quoteUserfieldItemResult->XML_ID); $this->assertTrue( $this->userfieldService->update( @@ -91,17 +96,13 @@ public function testUpdate(array $newUserFieldItem): void ); $ufFieldAfter = $this->userfieldService->get($newUserfieldId)->userfieldItem(); - $this->assertEquals($leadUserfieldItemResult->EDIT_FORM_LABEL['en'] . 'QQQ', $ufFieldAfter->EDIT_FORM_LABEL['en']); + $this->assertEquals($quoteUserfieldItemResult->EDIT_FORM_LABEL['en'] . 'QQQ', $ufFieldAfter->EDIT_FORM_LABEL['en']); } public function testList(): void { - $leadUserfieldsResult = $this->userfieldService->list([], []); - $this->assertGreaterThanOrEqual(0, count($leadUserfieldsResult->getUserfields())); + $quoteUserfieldsResult = $this->userfieldService->list([], []); + $this->assertGreaterThanOrEqual(0, count($quoteUserfieldsResult->getUserfields())); } - protected function setUp(): void - { - $this->userfieldService = Fabric::getServiceBuilder()->getCRMScope()->leadUserfield(); - } -} \ No newline at end of file +} diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldUseCaseTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldUseCaseTest.php index bfc333c6..8d0badab 100644 --- a/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldUseCaseTest.php +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteUserfieldUseCaseTest.php @@ -11,60 +11,24 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Quote\Service; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; -use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; -use Bitrix24\SDK\Services\CRM\Lead\Service\LeadUserfield; +use Bitrix24\SDK\Services\CRM\Quote\Service\Quote; +use Bitrix24\SDK\Services\CRM\Quote\Service\QuoteUserfield; use Bitrix24\SDK\Tests\Integration\Fabric; use PHPUnit\Framework\TestCase; -#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Lead\Service\LeadUserfield::class)] -class LeadUserfieldUseCaseTest extends TestCase +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\Quote\Service\QuoteUserfield::class)] +class QuoteUserfieldUseCaseTest extends TestCase { - protected Lead $leadService; + protected Quote $quoteService; - protected LeadUserfield $leadUserfieldService; - - protected int $leadUserfieldId; - - /** - * @throws BaseException - * @throws TransportException - */ - public function testOperationsWithUserfieldFromLeadItem(): void - { - // get userfield metadata - $leadUserfieldItemResult = $this->leadUserfieldService->get($this->leadUserfieldId)->userfieldItem(); - $ufOriginalFieldName = $leadUserfieldItemResult->getOriginalFieldName(); - $ufFieldName = $leadUserfieldItemResult->FIELD_NAME; - - // add lead with uf value - $fieldNameValue = 'test field value'; - $newLeadId = $this->leadService->add( - [ - 'TITLE' => 'test lead', - $ufFieldName => $fieldNameValue, - ] - )->getId(); - $lead = $this->leadService->get($newLeadId)->lead(); - $this->assertEquals($fieldNameValue, $lead->getUserfieldByFieldName($ufOriginalFieldName)); - - // update lead userfield value - $newUfValue = 'test 2'; - $this->assertTrue( - $this->leadService->update( - $lead->ID, - [ - $ufFieldName => $newUfValue, - ] - )->isSuccess() - ); - $leadItemResult = $this->leadService->get($lead->ID)->lead(); - $this->assertEquals($newUfValue, $leadItemResult->getUserfieldByFieldName($ufOriginalFieldName)); - } + protected QuoteUserfield $quoteUserfieldService; + protected int $quoteUserfieldId; + /** * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException * @throws \Bitrix24\SDK\Core\Exceptions\TransportException @@ -73,10 +37,10 @@ public function testOperationsWithUserfieldFromLeadItem(): void */ protected function setUp(): void { - $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); - $this->leadUserfieldService = Fabric::getServiceBuilder()->getCRMScope()->leadUserfield(); + $this->quoteService = Fabric::getServiceBuilder()->getCRMScope()->quote(); + $this->quoteUserfieldService = Fabric::getServiceBuilder()->getCRMScope()->quoteUserfield(); - $this->leadUserfieldId = $this->leadUserfieldService->add( + $this->quoteUserfieldId = $this->quoteUserfieldService->add( [ 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), 'EDIT_FORM_LABEL' => [ @@ -98,6 +62,43 @@ protected function setUp(): void protected function tearDown(): void { - $this->leadUserfieldService->delete($this->leadUserfieldId); + $this->quoteUserfieldService->delete($this->quoteUserfieldId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testOperationsWithUserfieldFromQuoteItem(): void + { + // get userfield metadata + $quoteUserfieldItemResult = $this->quoteUserfieldService->get($this->quoteUserfieldId)->userfieldItem(); + $ufOriginalFieldName = $quoteUserfieldItemResult->getOriginalFieldName(); + $ufFieldName = $quoteUserfieldItemResult->FIELD_NAME; + + // add quote with uf value + $fieldNameValue = 'test field value'; + $newQuoteId = $this->quoteService->add( + [ + 'TITLE' => 'test quote', + $ufFieldName => $fieldNameValue, + ] + )->getId(); + $quote = $this->quoteService->get($newQuoteId)->quote(); + $this->assertEquals($fieldNameValue, $quote->getUserfieldByFieldName($ufOriginalFieldName)); + + // update quote userfield value + $newUfValue = 'test 2'; + $this->assertTrue( + $this->quoteService->update( + $quote->ID, + [ + $ufFieldName => $newUfValue, + ] + )->isSuccess() + ); + $quoteItemResult = $this->quoteService->get($quote->ID)->quote(); + $this->assertEquals($newUfValue, $quoteItemResult->getUserfieldByFieldName($ufOriginalFieldName)); } -} \ No newline at end of file + +} From 8f6a427da5dd22425fe75dc60fe771b9964b7b98 Mon Sep 17 00:00:00 2001 From: Vadim Soluyanov Date: Fri, 20 Jun 2025 11:28:54 +0400 Subject: [PATCH 5/8] run tests on crm.quote.* --- .../CRM/Quote/Result/QuoteItemResult.php | 18 +++++++++++++++--- src/Services/CRM/Quote/Service/Quote.php | 14 ++++++++++++-- .../CustomBitrix24Assertions.php | 4 +++- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/Services/CRM/Quote/Result/QuoteItemResult.php b/src/Services/CRM/Quote/Result/QuoteItemResult.php index 28ed5b2f..eca05b4e 100644 --- a/src/Services/CRM/Quote/Result/QuoteItemResult.php +++ b/src/Services/CRM/Quote/Result/QuoteItemResult.php @@ -28,9 +28,19 @@ * @property-read int $ID * @property-read string $TITLE * @property-read int|null $ASSIGNED_BY_ID - * @property-read CarbonImmutable|null $BEGINDATA - * @property-read CarbonImmutable|null $CLOSEDATA + * @property-read int|null $LAST_ACTIVITY_BY + * @property-read CarbonImmutable|null $LAST_ACTIVITY_TIME + * @property-read string|null $LAST_COMMUNICATION_TIME + * @property-read CarbonImmutable|null $BEGINDATE + * @property-read CarbonImmutable|null $CLOSEDATE + * @property-read CarbonImmutable|null $ACTUAL_DATE * @property-read string|null $CLIENT_ADDR + * @property-read string|null $CLIENT_CONTACT + * @property-read string|null $CLIENT_EMAIL + * @property-read string|null $CLIENT_PHONE + * @property-read string|null $CLIENT_TITLE + * @property-read string|null $CLIENT_TPA_ID + * @property-read string|null $CLIENT_TP_ID * @property-read bool|null $CLOSED * @property-read string|null $COMMENTS * @property-read int|null $COMPANY_ID @@ -44,12 +54,14 @@ * @property-read int|null $DEAL_ID * @property-read int|null $LEAD_ID * @property-read int|null $LOCATION_ID + * @property-read int|null $MODIFY_BY_ID + * @property-read int|null $MYCOMPANY_ID * @property-read bool|null $OPENED * @property-read Money|null $OPPORTUNITY * @property-read int|null $PERSON_TYPE_ID * @property-read string|null $QUOTE_NUMBER * @property-read string|null $STATUS_ID - * @property-read string|null $TAX_VALUE + * @property-read Money|null $TAX_VALUE * @property-read string|null $TERMS * @property-read string|null $UTM_SOURCE * @property-read string|null $UTM_MEDIUM diff --git a/src/Services/CRM/Quote/Service/Quote.php b/src/Services/CRM/Quote/Service/Quote.php index b3b2bceb..75ce8e88 100644 --- a/src/Services/CRM/Quote/Service/Quote.php +++ b/src/Services/CRM/Quote/Service/Quote.php @@ -54,10 +54,20 @@ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $ * @param array{ * ID?: int, * ASSIGNED_BY_ID?: int, - * BEGINDATA?: string, + * LAST_ACTIVITY_BY?: int, + * LAST_ACTIVITY_TIME?: string, + * LAST_COMMUNICATION_TIME?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * ACTUAL_DATE?: string, * CLIENT_ADDR?: string, + * CLIENT_CONTACT?: string, + * CLIENT_EMAIL?: string, + * CLIENT_PHONE?: string, + * CLIENT_TITLE?: string, + * CLIENT_TPA_ID?: string, + * CLIENT_TP_ID?: string, * CLOSED?: bool, - * CLOSEDATA?: string, * COMMENTS?: string, * COMPANY_ID?: int, * CONTACT_ID?: int, diff --git a/tests/CustomAssertions/CustomBitrix24Assertions.php b/tests/CustomAssertions/CustomBitrix24Assertions.php index fb588da5..9b9c52b9 100644 --- a/tests/CustomAssertions/CustomBitrix24Assertions.php +++ b/tests/CustomAssertions/CustomBitrix24Assertions.php @@ -141,7 +141,6 @@ protected function assertBitrix24AllResultItemFieldsHasValidTypeAnnotation( break; case 'user': case 'crm_enum_ownertype': - case 'crm_lead': case 'integer': case 'int': $this->assertTrue( @@ -227,6 +226,9 @@ protected function assertBitrix24AllResultItemFieldsHasValidTypeAnnotation( case 'object': case 'crm_company': case 'crm_contact': + case 'crm_deal': + case 'crm_lead': + case 'location': case 'product_file': if (str_contains($fieldCode, '_IDS') || str_contains($fieldCode, 'PHOTO') || From 72082869ed207250a89b6621b0df7735d697054d Mon Sep 17 00:00:00 2001 From: Vadim Soluyanov Date: Fri, 20 Jun 2025 11:41:20 +0400 Subject: [PATCH 6/8] run linters --- .../Quote/Events/CrmQuoteEventsFactory.php | 4 +--- .../OnCrmQuoteUpdatePayload.php | 4 ++-- .../OnCrmQuoteUserFieldAdd.php | 3 +-- .../OnCrmQuoteUserFieldAddPayload.php | 2 +- .../OnCrmQuoteUserFieldDelete.php | 2 +- .../OnCrmQuoteUserFieldDeletePayload.php | 2 +- .../OnCrmQuoteUserFieldSetEnumValues.php | 2 +- ...nCrmQuoteUserFieldSetEnumValuesPayload.php | 2 +- .../OnCrmQuoteUserFieldUpdate.php | 2 +- .../OnCrmQuoteUserFieldUpdatePayload.php | 2 +- .../QuoteContactConnectionItemResult.php | 2 +- .../Result/QuoteContactConnectionResult.php | 2 +- .../CRM/Quote/Result/QuoteItemResult.php | 1 - src/Services/CRM/Quote/Service/Batch.php | 14 +++-------- src/Services/CRM/Quote/Service/Quote.php | 21 ++-------------- .../CRM/Quote/Service/QuoteContact.php | 24 +++++++++---------- .../CRM/Quote/Service/QuoteProductRows.php | 1 - .../CRM/Quote/Service/QuoteContactTest.php | 18 ++++++-------- .../Services/CRM/Quote/Service/QuoteTest.php | 2 +- 19 files changed, 38 insertions(+), 72 deletions(-) diff --git a/src/Services/CRM/Quote/Events/CrmQuoteEventsFactory.php b/src/Services/CRM/Quote/Events/CrmQuoteEventsFactory.php index 6003ea87..97c67361 100644 --- a/src/Services/CRM/Quote/Events/CrmQuoteEventsFactory.php +++ b/src/Services/CRM/Quote/Events/CrmQuoteEventsFactory.php @@ -11,10 +11,8 @@ declare(strict_types=1); - namespace Bitrix24\SDK\Services\CRM\Quote\Events; - use Bitrix24\SDK\Core\Contracts\Events\EventInterface; use Bitrix24\SDK\Core\Contracts\Events\EventsFabricInterface; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; @@ -65,4 +63,4 @@ public function create(Request $eventRequest): EventInterface ), }; } -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdatePayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdatePayload.php index 592a5cf6..3c34977a 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdatePayload.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUpdate/OnCrmQuoteUpdatePayload.php @@ -11,7 +11,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\CRM\Deal\Events\OnCrmDealRecurringUpdate; +namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUpdate; use Bitrix24\SDK\Core\Result\AbstractItem; @@ -21,6 +21,6 @@ * RECURRING_DEAL_ID: int, * } $FIELDS */ -class OnCrmDealRecurringUpdatePayload extends AbstractItem +class OnCrmQuoteUpdatePayload extends AbstractItem { } diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAdd.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAdd.php index c14e21d3..9c849b12 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAdd.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAdd.php @@ -14,7 +14,6 @@ namespace Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteUserFieldAdd; use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; -use Bitrix24\SDK\Services\CRM\Quote\Events\OnCrmQuoteAdd\OnCrmQuoteUserFieldAddPayload; class OnCrmQuoteUserFieldAdd extends AbstractEventRequest { @@ -24,4 +23,4 @@ public function getPayload(): OnCrmQuoteUserFieldAddPayload { return new OnCrmQuoteUserFieldAddPayload($this->eventPayload['data']); } -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAddPayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAddPayload.php index ce44b3f8..d56bf4fa 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAddPayload.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldAdd/OnCrmQuoteUserFieldAddPayload.php @@ -23,4 +23,4 @@ */ class OnCrmQuoteUserFieldAddPayload extends AbstractItem { -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDelete.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDelete.php index 95b3a3ed..42280462 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDelete.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDelete.php @@ -23,4 +23,4 @@ public function getPayload(): OnCrmQuoteUserFieldDeletePayload { return new OnCrmQuoteUserFieldDeletePayload($this->eventPayload['data']); } -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDeletePayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDeletePayload.php index e01d39fb..0650741c 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDeletePayload.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldDelete/OnCrmQuoteUserFieldDeletePayload.php @@ -23,4 +23,4 @@ */ class OnCrmQuoteUserFieldDeletePayload extends AbstractItem { -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValues.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValues.php index d67a3cd9..a8ec9e53 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValues.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValues.php @@ -23,4 +23,4 @@ public function getPayload(): OnCrmQuoteUserFieldSetEnumValuesPayload { return new OnCrmQuoteUserFieldSetEnumValuesPayload($this->eventPayload['data']); } -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValuesPayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValuesPayload.php index 8390e369..b366c5ee 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValuesPayload.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldSetEnumValues/OnCrmQuoteUserFieldSetEnumValuesPayload.php @@ -23,4 +23,4 @@ */ class OnCrmQuoteUserFieldSetEnumValuesPayload extends AbstractItem { -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdate.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdate.php index 940b84ba..fcdb5130 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdate.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdate.php @@ -23,4 +23,4 @@ public function getPayload(): OnCrmQuoteUserFieldUpdatePayload { return new OnCrmQuoteUserFieldUpdatePayload($this->eventPayload['data']); } -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdatePayload.php b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdatePayload.php index 4c24465c..05a71a68 100644 --- a/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdatePayload.php +++ b/src/Services/CRM/Quote/Events/OnCrmQuoteUserFieldUpdate/OnCrmQuoteUserFieldUpdatePayload.php @@ -23,4 +23,4 @@ */ class OnCrmQuoteUserFieldUpdatePayload extends AbstractItem { -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Result/QuoteContactConnectionItemResult.php b/src/Services/CRM/Quote/Result/QuoteContactConnectionItemResult.php index 43916b47..12b20524 100644 --- a/src/Services/CRM/Quote/Result/QuoteContactConnectionItemResult.php +++ b/src/Services/CRM/Quote/Result/QuoteContactConnectionItemResult.php @@ -22,4 +22,4 @@ */ class QuoteContactConnectionItemResult extends AbstractCrmItem { -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Result/QuoteContactConnectionResult.php b/src/Services/CRM/Quote/Result/QuoteContactConnectionResult.php index fcc89f99..3af3cd83 100644 --- a/src/Services/CRM/Quote/Result/QuoteContactConnectionResult.php +++ b/src/Services/CRM/Quote/Result/QuoteContactConnectionResult.php @@ -32,4 +32,4 @@ public function getContactConnections(): array return $res; } -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Result/QuoteItemResult.php b/src/Services/CRM/Quote/Result/QuoteItemResult.php index eca05b4e..9475b36f 100644 --- a/src/Services/CRM/Quote/Result/QuoteItemResult.php +++ b/src/Services/CRM/Quote/Result/QuoteItemResult.php @@ -72,7 +72,6 @@ class QuoteItemResult extends AbstractCrmItem { /** - * @param string $userfieldName * * @return mixed|null * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException diff --git a/src/Services/CRM/Quote/Service/Batch.php b/src/Services/CRM/Quote/Service/Batch.php index 772d89d5..59496c2a 100644 --- a/src/Services/CRM/Quote/Service/Batch.php +++ b/src/Services/CRM/Quote/Service/Batch.php @@ -28,19 +28,11 @@ #[ApiBatchServiceMetadata(new Scope(['crm']))] class Batch { - protected BatchOperationsInterface $batch; - protected LoggerInterface $log; - /** * Batch constructor. - * - * @param BatchOperationsInterface $batch - * @param LoggerInterface $log */ - public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) + public function __construct(protected BatchOperationsInterface $batch, protected LoggerInterface $log) { - $this->batch = $batch; - $this->log = $log; } /** @@ -118,7 +110,6 @@ public function __construct(BatchOperationsInterface $batch, LoggerInterface $lo * UTM_TERM?: string, * } $filter * @param array $select = ['ID','ASSIGNED_BY_ID','BEGINDATA','CLIENT_ADDR','CLOSED','CLOSEDATA','COMMENTS','COMPANY_ID','CONTACT_ID','CONTACT_IDS','CONTENT','CREATED_BY_ID','CURRENCY_ID','DATE_CREATE','DATE_MODIFY','DEAL_ID','LEAD_ID','LOCATION_ID','MODIFY_BY_ID','MYCOMPANY_ID','OPENED','OPPORTUNITY','PERSON_TYPE_ID','QUOTE_NUMBER','STATUS_ID','TAX_VALUE','TERMS','TITLE','UTM_CAMPAIGN','UTM_CONTENT','UTM_MEDIUM','UTM_SOURCE','UTM_TERM'] - * @param int|null $limit * * @return Generator * @throws BaseException @@ -199,11 +190,12 @@ public function add(array $quotes): Generator 'fields' => $quote, ]; } + foreach ($this->batch->addEntityItems('crm.quote.add', $items) as $key => $item) { yield $key => new AddedItemBatchResult($item); } } - + /** * Batch update quotes * diff --git a/src/Services/CRM/Quote/Service/Quote.php b/src/Services/CRM/Quote/Service/Quote.php index 75ce8e88..db47bd18 100644 --- a/src/Services/CRM/Quote/Service/Quote.php +++ b/src/Services/CRM/Quote/Service/Quote.php @@ -31,19 +31,12 @@ #[ApiServiceMetadata(new Scope(['crm']))] class Quote extends AbstractService { - public Batch $batch; - /** * Quote constructor. - * - * @param Batch $batch - * @param CoreInterface $core - * @param LoggerInterface $log */ - public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $log) + public function __construct(public Batch $batch, CoreInterface $core, LoggerInterface $logger) { - parent::__construct($core, $log); - $this->batch = $batch; + parent::__construct($core, $logger); } /** @@ -97,7 +90,6 @@ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $ * UTM_TERM?: string, * } $fields * - * @return AddedItemResult * @throws BaseException * @throws TransportException */ @@ -123,9 +115,7 @@ public function add(array $fields): AddedItemResult * * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-delete.html * - * @param int $id * - * @return DeletedItemResult * @throws BaseException * @throws TransportException */ @@ -151,7 +141,6 @@ public function delete(int $id): DeletedItemResult * * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-fields.html * - * @return FieldsResult * @throws BaseException * @throws TransportException */ @@ -170,9 +159,7 @@ public function fields(): FieldsResult * * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-get.html * - * @param int $id * - * @return QuoteResult * @throws BaseException * @throws TransportException */ @@ -198,7 +185,6 @@ public function get(int $id): QuoteResult * * @throws BaseException * @throws TransportException - * @return QuotesResult */ #[ApiEndpointMetadata( 'crm.quote.list', @@ -225,7 +211,6 @@ public function list(array $order, array $filter, array $select, int $startItem * * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-update.html * - * @param int $id * @param array{ * ID?: int, * ASSIGNED_BY_ID?: int, @@ -262,7 +247,6 @@ public function list(array $order, array $filter, array $select, int $startItem * UTM_TERM?: string, * } $fields * - * @return UpdatedItemResult * @throws BaseException * @throws TransportException */ @@ -323,7 +307,6 @@ public function update(int $id, array $fields): UpdatedItemResult * UTM_TERM?: string, * } $filter * - * @return int * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @throws \Bitrix24\SDK\Core\Exceptions\TransportException */ diff --git a/src/Services/CRM/Quote/Service/QuoteContact.php b/src/Services/CRM/Quote/Service/QuoteContact.php index 00ad1ac0..910504e4 100644 --- a/src/Services/CRM/Quote/Service/QuoteContact.php +++ b/src/Services/CRM/Quote/Service/QuoteContact.php @@ -36,7 +36,6 @@ class QuoteContact extends AbstractService * * @link https://apidocs.bitrix24.com/api-reference/crm/quote/index.html * - * @return FieldsResult * @throws BaseException * @throws TransportException */ @@ -66,19 +65,20 @@ public function fields(): FieldsResult public function setItems(int $quoteId, array $contactConnections): UpdatedItemResult { $items = []; - foreach ($contactConnections as $item) { - if (!$item instanceof ContactConnection) { + foreach ($contactConnections as $contactConnection) { + if (!$contactConnection instanceof ContactConnection) { throw new InvalidArgumentException( - sprintf('array item «%s» must be «%s» type', gettype($item), ContactConnection::class) + sprintf('array item «%s» must be «%s» type', gettype($contactConnection), ContactConnection::class) ); } $items[] = [ - 'CONTACT_ID' => $item->contactId, - 'SORT' => $item->sort, - 'IS_PRIMARY' => $item->isPrimary ? 'Y' : 'N' + 'CONTACT_ID' => $contactConnection->contactId, + 'SORT' => $contactConnection->sort, + 'IS_PRIMARY' => $contactConnection->isPrimary ? 'Y' : 'N' ]; } + if ($items === []) { throw new InvalidArgumentException('empty contact connections array'); } @@ -138,14 +138,14 @@ public function deleteItems(int $quoteId): DeletedItemResult 'https://apidocs.bitrix24.com/api-reference/crm/quote/index.html', 'Add Contact to the Specified Estimate' )] - public function add(int $quoteId, ContactConnection $connection): UpdatedItemResult + public function add(int $quoteId, ContactConnection $contactConnection): UpdatedItemResult { return new UpdatedItemResult($this->core->call('crm.quote.contact.add', [ 'id' => $quoteId, 'fields' => [ - 'CONTACT_ID' => $connection->contactId, - 'SORT' => $connection->sort, - 'IS_PRIMARY' => $connection->isPrimary ? 'Y' : 'N' + 'CONTACT_ID' => $contactConnection->contactId, + 'SORT' => $contactConnection->sort, + 'IS_PRIMARY' => $contactConnection->isPrimary ? 'Y' : 'N' ] ])); } @@ -171,4 +171,4 @@ public function delete(int $quoteId, int $contactId): DeletedItemResult ] ])); } -} \ No newline at end of file +} diff --git a/src/Services/CRM/Quote/Service/QuoteProductRows.php b/src/Services/CRM/Quote/Service/QuoteProductRows.php index 6a737f0b..3a224552 100644 --- a/src/Services/CRM/Quote/Service/QuoteProductRows.php +++ b/src/Services/CRM/Quote/Service/QuoteProductRows.php @@ -72,7 +72,6 @@ public function get(int $quoteId, Currency $currency = null): QuoteProductRowIte * * @link https://apidocs.bitrix24.com/api-reference/crm/quote/crm-quote-product-rows-set.html * - * @param int $quoteId * @param arraysb = Fabric::getServiceBuilder(); } - public function tearDown(): void + protected function tearDown(): void { - foreach ($this->sb->getCRMScope()->quote()->batch->delete($this->createdQuotes) as $result) { - } - - foreach ($this->sb->getCRMScope()->contact()->batch->delete($this->createdContacts) as $result) { - } } public function testSet(): void @@ -73,8 +69,8 @@ public function testSet(): void $connectedId = [$contactIdOne, $contactIdTwo]; $connectedContacts = $this->sb->getCRMScope()->quoteContact()->get($quoteId)->getContactConnections(); - foreach ($connectedContacts as $item) { - $this->assertContains($item->CONTACT_ID, $connectedId); + foreach ($connectedContacts as $connectedContact) { + $this->assertContains($connectedContact->CONTACT_ID, $connectedId); } } @@ -106,8 +102,8 @@ public function testAdd(): void $connectedId = [$contactIdOne, $contactIdTwo]; $connectedContacts = $this->sb->getCRMScope()->quoteContact()->get($quoteId)->getContactConnections(); - foreach ($connectedContacts as $item) { - $this->assertContains($item->CONTACT_ID, $connectedId); + foreach ($connectedContacts as $connectedContact) { + $this->assertContains($connectedContact->CONTACT_ID, $connectedId); } } diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteTest.php index 1d851006..ac6cf2ad 100644 --- a/tests/Integration/Services/CRM/Quote/Service/QuoteTest.php +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteTest.php @@ -121,7 +121,7 @@ public function testUpdate(): void $addedItemResult = $this->quoteService->add(['TITLE' => 'test quote']); $newTitle = 'test2'; - self::assertTrue($this->quoteService->update($addedItemResult->getId(), ['TITLE' => $newTitle], [])->isSuccess()); + self::assertTrue($this->quoteService->update($addedItemResult->getId(), ['TITLE' => $newTitle])->isSuccess()); self::assertEquals($newTitle, $this->quoteService->get($addedItemResult->getId())->quote()->TITLE); } From ba58f81b7b33cdc3305262928579975a839f2607 Mon Sep 17 00:00:00 2001 From: Vadim Soluyanov Date: Fri, 20 Jun 2025 11:46:42 +0400 Subject: [PATCH 7/8] restore lines deleted by linters --- .../Services/CRM/Quote/Service/QuoteContactTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php index 86bc5b30..ec38bd66 100644 --- a/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php @@ -49,6 +49,12 @@ protected function setUp(): void protected function tearDown(): void { + foreach ($this->sb->getCRMScope()->quote()->batch->delete($this->createdQuotes) as $result) { + // ### + } + foreach ($this->sb->getCRMScope()->contact()->batch->delete($this->createdContacts) as $result) { + // ### + } } public function testSet(): void From 9dbb78b1e363bf8e75322f71e7dd46c5c0c49b35 Mon Sep 17 00:00:00 2001 From: Vadim Soluyanov Date: Fri, 20 Jun 2025 11:50:32 +0400 Subject: [PATCH 8/8] add new line for lint-rector --- .../Integration/Services/CRM/Quote/Service/QuoteContactTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php b/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php index ec38bd66..3e5a0718 100644 --- a/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php +++ b/tests/Integration/Services/CRM/Quote/Service/QuoteContactTest.php @@ -52,6 +52,7 @@ protected function tearDown(): void foreach ($this->sb->getCRMScope()->quote()->batch->delete($this->createdQuotes) as $result) { // ### } + foreach ($this->sb->getCRMScope()->contact()->batch->delete($this->createdContacts) as $result) { // ### }