PHP code example of iperson1337 / nct-client-bundle

1. Go to this page and download the library: Download iperson1337/nct-client-bundle library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

iperson1337 / nct-client-bundle example snippets


// config/bundles.php
return [
    // ...
    Iperson1337\NctClientBundle\NctClientBundle::class => ['all' => true],
];

use Iperson1337\NctClientBundle\Exception\NctProductNotFoundException;
use Iperson1337\NctClientBundle\NctClient;

final class NtinLookup
{
    public function __construct(private readonly NctClient $nct) {}

    public function ntinFor(string $gtin): ?string
    {
        try {
            $card = $this->nct->fetchProductByGtin($gtin);

            // nct.gov.kz returns `ntin_code`; the portal returns `ntin`
            return $card['ntin'] ?? $card['ntin_code'] ?? null;
        } catch (NctProductNotFoundException) {
            return null; // no card for this GTIN — a regular outcome, not a failure
        }
    }
}

$card = $this->nct->fetchProductByGtin($gtin, timeoutOverride: 3.0, maxAttempts: 1);

$cards = $this->nct->portal()->fetchProductsByTin('4870001302818');   // GET /v2/products/{tin}

use Iperson1337\NctClientBundle\Request\ProductRequestPayload;

$portal = $this->nct->portal();

$payload = new ProductRequestPayload(
    oktru: '10.51.11',
    autoPublication: false,
    attributes: [
        ['code' => 'gtin', 'value' => '4870001302818'],
        ['code' => 'name_ru', 'value' => 'Молоко 2,5% 1 л'],
    ],
);

$requestId = (int) $portal->submitProductRequest($payload->toArray())['id'];   // POST …/requests → draft

$portal->submitToModeration($requestId);                       // PUT …/{id}/moderation (new, underRevision)
$portal->cancelRequest($requestId);                            // PUT …/{id}/cancel     (onModeration → cancelled)
$portal->updateProductRequest($requestId, $payload->toArray()); // PUT …/{id}            (new, underRevision, cancelled)
$portal->publishRequest($requestId);                           // PUT …/{id}/publish    (readyToPublish)
$portal->deleteProductRequest($requestId);                     // DELETE …/{id}         (new only)

$draft = $portal->createEditRequest('0200212305195');   // POST …/requests/{ntin}/edit-product
$requestId = (int) $draft['productRequestId'];
$body = ProductRequestPayload::fromArray($draft);       // same shape as PUT …/requests/{id}
// `oktru` may come back null for old cards — set a current category code before sending.
$portal->updateProductRequest($requestId, $body->toArray());

if (!$payload->matchesStoredJson($request->getRequestBody())) {
    $portal->updateProductRequest($requestId, $payload->toArray());
}

use Iperson1337\NctClientBundle\Request\RequestDetailsParser;
use Iperson1337\NctClientBundle\Request\RequestStatus;

$status = $portal->fetchRequestStatus($requestId);
// ['code' => 'completed', 'value' => '…', 'ntinCode' => '0200…', 'productUrl' => '…',
//  'comment' => …, 'revisionDetails' => [...], 'nextAction' => [...], 'gzStatus' => [...]]
$code = RequestStatus::tryFrom($status['code']);
if ($code?->isFinal()) { /* completed, rejected or existingProductSelected */ }

$details = $portal->fetchRequestDetails($requestId, timeoutOverride: 3.0, maxAttempts: 1);
$parser  = new RequestDetailsParser();
$ntin    = $parser->extractAttributeValueByCode($details, 'ntin');
$xtin    = $parser->extractAttributeValueByCode($details, 'xtin');
$comment = $parser->extractModeratorComment($details);        // null — absent; '' — present but empty

$page = $portal->fetchProductRequests(page: 1, size: 50, status: RequestStatus::OnModeration);
// ['content' => [...], 'totalElements' => N, 'totalPages' => M]

use Iperson1337\NctClientBundle\Portal\DuplicateDecision;

$matches = $portal->fetchDuplicates($requestId);   // orderNumber, name, brand, gtin, ntin, similarity
$portal->decideDuplicates($requestId, DuplicateDecision::UseExisting, $matches[0]['ntin']);
// or: $portal->decideDuplicates($requestId, DuplicateDecision::Continue);

use Iperson1337\NctClientBundle\Portal\ImageType;

$front = $portal->uploadPhoto($requestId, ImageType::Front, '/path/front.jpg');     // POST …/storage/{id}/upload?imageType=front
$back  = $portal->uploadPhoto($requestId, ImageType::Back, fopen('php://memory', 'r+'), 'back.jpg');
$cert  = $portal->uploadDocument($requestId, '/path/certificate.pdf');              // POST …/storage/{id}/upload/document
$portal->deleteFile($requestId, $cert['filename']);                                 // DELETE …/storage/{id}/{fileName}

$payload = new ProductRequestPayload(
    oktru: '10.51.11',
    autoPublication: false,
    attributes: [/* … incl. ['code' => 'brand', 'value' => '…'] */],
    isGov: true,
    mainExtendedAttributes: [['code' => 'gross_weight', 'value' => '1.05']],
    additionalExtendedAttributes: [/* from fetchGovAttributes() */],
    imageFiles: [
        ['fileName' => $front['filename'], 'imageType' => ImageType::Front->value],
        ['fileName' => $back['filename'], 'imageType' => ImageType::Back->value],
    ],
    documents: [['fileName' => $cert['filename']]],
);

use Iperson1337\NctClientBundle\Attribute\AttributeDefinition;
use Iperson1337\NctClientBundle\Dictionary\DictionaryItem;

foreach ($portal->fetchAttributes() as $row) {                 // GET …/requests/attributes
    if (AttributeDefinition::missingRequiredFields($row) !== []) {
        continue;
    }
    $definition = AttributeDefinition::fromPortalRow($row);
    // $definition->code, ->dataType ('string'|'text'|'number'|'boolean'|'dictionary'|'multiDictionary'|'date'),
    // ->isRequired, ->maxLength, ->pattern, ->dictionaryCode, ->dictionaryValues …
}

$gov = $portal->fetchGovAttributes('10.51.11');                // mainAttributes + additionalAttributes per ОКТРУ

$dictionaries = $portal->fetchDictionaries();                   // GET …/dictionaries
$roots = $portal->fetchDictionaryRoots('MEASURE_UNIT');         // tree dictionaries
$children = $portal->fetchDictionaryChildren('MEASURE_UNIT', (int) $roots[0]['id']);
$page = $portal->fetchDictionaryItems('TNVED', page: 1, size: 100);   // any dictionary, paged (size 1..100)

foreach ($roots as $row) {
    if (DictionaryItem::missingRequiredField($row) === null) {
        $item = DictionaryItem::fromRow($row);                 // externalId, code, nameRu, nameKk, parentId, level, hasChild, isDeleted
    }
}

$gov = $this->nct->gov();

$cards = $gov->searchByGtin($gtin);                          // every card with this code, incl. deactivated duplicates; [] if none
$cards = $gov->searchByTins(['4870235770032', '0200093179779']);   // up to 100 NTIN/GTIN per request
$page  = $gov->searchByName('Молоко', limit: 100, offset: 0);     // ['count', 'next', 'previous', 'last_modified', 'result' => [...]]
$card  = $gov->findActiveCard($gtin);                        // first card with ntin_isdeactivated === false; null if all are deactivated
$ntin  = $gov->lookupNtin($gtin);                            // ['gtin' => …, 'ntin_code' => string|null]; throws if there are no cards
$full  = $gov->fetchProduct((int) $card['id']);              // GET /api/core/products/{id}; category.full_code holds ОКТРУ

$auth = $gov->login('username', 'password');                 // POST /api/auth/login/ — raw response with the JWT
$jwt = $auth['access'] ?? $auth['token'];                    // key name depends on the portal's response

$count = $gov->countChangedProducts($jwt, from: 1743596160)['count'];
$page = $gov->exportProducts($jwt, from: 1743596160, limit: 1000, offset: 0);
foreach ($page['result'] as $card) {
    // id, name_ru, name_kk, gtin, ntin_code, is_social, modified, status, is_markedeac, measure,
    // product_type (1 goods, 2 work, 3 service), ntin_isdeactivated, ntin_deactivationreason, ntin_duplicateofproduct
}
// next call: from = the largest `modified` received

use Iperson1337\NctClientBundle\Identifier\NationalCatalogIdentifier;

$id = new NationalCatalogIdentifier();
$id->isValidNtin('0200212305195');  // true — "02" + 11 digits
$id->isValidXtin('0040212305191');  // true — "004" + 10 digits
$id->normalize('  0200212305195 '); // '0200212305195'; blank → null