PHP code example of snipershady / amilon

1. Go to this page and download the library: Download snipershady/amilon 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/ */

    

snipershady / amilon example snippets


use Amilon\Dto\CredentialDto;
use Amilon\Dto\Request\CreateOrderRequestDto;
use Amilon\Enum\CountryEnum;
use Amilon\Enum\Environment;
use Amilon\Service\AmilonClientFactory;

$client = AmilonClientFactory::create(new CredentialDto(
    username:     $secrets->get('amilon_username'),
    password:     $secrets->get('amilon_password'),
    clientId:     $secrets->get('amilon_client_id'),
    clientSecret: $secrets->get('amilon_client_secret'),
    authDomain:   'https://b2bstg-sso.amilon.eu/',
    webDomain:    'https://b2bstg-webapi.amilon.eu/b2bwebapi/v1/',
    webDomainV2:  'https://b2bstg-webapi.amilon.eu/b2bwebapi/v2/',
    contractId:   '1ab2c3d4-567e-4b0c-b8da-a3ed94ae6392',
    environment:  Environment::STAGING,
));

// browse the catalogue: one entry per merchant, each with a list of denominations
$merchants = $client->getDenominations(CountryEnum::IT);
foreach ($merchants as $merchant) {
    foreach ($merchant->denominations as $denomination) {
        // denomination shape: ->isFixed() / ->isVariable() / ->hasContractPriceOverride()
        $price = $denomination->prices[0]->price ?? $denomination->rangeMin;
        echo $merchant->code, ' ', $merchant->name, ' ', $price, PHP_EOL;
    }
}

// place an order: identify the item by merchant code + chosen face value.
// pick the first denomination that can actually be ordered — one with an
// explicit price or an open range (skip a denomination that has neither)
$merchant = $merchants->all()[0];
$denomination = $merchant->denominations[0];
foreach ($merchants as $candidate) {
    foreach ($candidate->denominations as $option) {
        if ([] !== $option->prices || $option->isVariable()) {
            [$merchant, $denomination] = [$candidate, $option];
            break 2;
        }
    }
}
$price = $denomination->prices[0]->price ?? $denomination->rangeMin;

$order = $client->makeOrder(
    CreateOrderRequestDto::singleLineWithPrice('my-order-001', $merchant->code, 1, $price),
);

foreach ($order->vouchers as $voucher) {
    echo $voucher->voucherLink, PHP_EOL;
}

// read it back later — summary only, or ...Complete() for the vouchers too
$order = $client->getOrderInfoComplete('my-order-001');

// check the spendable balance
echo $client->getContractInfo()->currentAmount, PHP_EOL;

$token = $client->getToken();

$token->authorizationHeader();   // "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6..."
$token->isExpired();             // false

use Amilon\Enum\CountryEnum;

$merchants = $client->getDenominations(CountryEnum::IT);

foreach ($merchants as $merchant) {
    foreach ($merchant->denominations as $denomination) {
        $amount = $denomination->prices[0]->price ?? $denomination->rangeMin;
        echo $merchant->name, ' ', $amount, ' ', $merchant->currencySymbol, PHP_EOL;
    }
}

use Amilon\Enum\CountryEnum;

$merchants = $client->getDenominationsComplete(CountryEnum::IT);

$content = $merchants->all()[0]->extendedContent;   // MerchantContentDto
echo $content->termsAndConditions, PHP_EOL;

use Amilon\Enum\CountryEnum;

$products = $client->getProducts(CountryEnum::IT);

foreach ($products as $product) {
    echo $product->name, ' — ', $product->price, PHP_EOL;   // "Carrefour - 20,00 € — 20"
}

use Amilon\Enum\CountryEnum;

$retailers = $client->getRetailers(CountryEnum::IT);

foreach ($retailers as $retailer) {
    echo $retailer->name, ' (', $retailer->codeValidityMonths, ' months)', PHP_EOL;
}

$categories = $client->getRetailerCategories();

foreach ($categories as $category) {
    echo $category->categoryId, ' => ', $category->categoryName, PHP_EOL;
}

use Amilon\Dto\Request\CreateOrderRequestDto;
use Amilon\Dto\Request\OrderLineDto;

// one merchant, one face value
$order = $client->makeOrder(
    CreateOrderRequestDto::singleLineWithPrice('my-order-001', $merchantCode, 1, 20.0),
);

// or several merchants in a single order
$order = $client->makeOrder(CreateOrderRequestDto::fromLines('my-order-002', [
    OrderLineDto::withPrice($merchantCodeA, 2, 25.0),
    OrderLineDto::withPrice($merchantCodeB, 1, 50.0),
]));

foreach ($order->vouchers as $voucher) {
    echo $voucher->voucherLink, PHP_EOL;
}

$order = $client->makeOrderPostponed(
    CreateOrderRequestDto::singleLineWithPrice('my-order-003', $merchantCode, 1, 20.0),
    new DateTimeImmutable('+7 days'),
);

$order->orderStatus;   // e.g. "Pending"  (->status() is null — not a modelled state)
$order->vouchers;       // [] — issued later

$order = $client->getOrderInfo('my-order-003');

echo $order->orderStatus, ' — ', $order->totalRequestedCodes, ' code(s)', PHP_EOL;

$order = $client->getOrderInfoComplete('my-order-003');

if ($order->status()?->isCompleted()) {
    foreach ($order->vouchers as $voucher) {
        echo $voucher->voucherLink, PHP_EOL;
    }
}

$info = $client->getContractInfo();

if ($info->currentAmount < 100.0) {
    // top up before ordering
}

// every denomination in an order must be priced in this currency
$currency = $info->currencyIsoCode;   // e.g. "EUR"

use Amilon\Enum\AmilonErrorCode;
use Amilon\Exception\AmilonExceptionInterface;
use Amilon\Exception\ApiRequestException;

try {
    $order = $client->makeOrder($request);
} catch (ApiRequestException $e) {
    if (AmilonErrorCode::INSUFFICIENT_CONTRACT_CREDIT === $e->errorCode) {
        // top up the contract and retry
    }
    if ($e->isTransient()) {
        // 0000 / 0500 — safe to retry with the same input
    }
} catch (AmilonExceptionInterface $e) {
    // any other failure originating from the Amilon integration
}

// src/Amilon/AmilonClientFactory.php
namespace App\Amilon;

use Amilon\Dto\CredentialDto;
use Amilon\Enum\Environment;
use Amilon\Service\AmilonClient;
use Amilon\Service\AmilonClientFactory as LibraryAmilonClientFactory;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

final class AmilonClientFactory
{
    public function __construct(
        #[Autowire('%env(AMILON_USERNAME)%')]
        private readonly string $username,
        #[Autowire('%env(AMILON_PASSWORD)%')]
        private readonly string $password,
        #[Autowire('%env(AMILON_CLIENT_ID)%')]
        private readonly string $clientId,
        #[Autowire('%env(AMILON_CLIENT_SECRET)%')]
        private readonly string $clientSecret,
        #[Autowire('%env(AMILON_AUTH_DOMAIN)%')]
        private readonly string $authDomain,
        #[Autowire('%env(AMILON_WEB_DOMAIN)%')]
        private readonly string $webDomain,
        #[Autowire('%env(AMILON_WEB_DOMAIN_V2)%')]
        private readonly string $webDomainV2,
        #[Autowire('%env(AMILON_CONTRACT_ID)%')]
        private readonly string $contractId,
        #[Autowire('%env(AMILON_ENVIRONMENT)%')] // "staging" or "production"
        private readonly string $environment,
    ) {
    }

    public function create(): AmilonClient
    {
        return LibraryAmilonClientFactory::create(new CredentialDto(
            username: $this->username,
            password: $this->password,
            clientId: $this->clientId,
            clientSecret: $this->clientSecret,
            authDomain: $this->authDomain,
            webDomain: $this->webDomain,
            webDomainV2: $this->webDomainV2,
            contractId: $this->contractId,
            environment: Environment::from($this->environment),
        ));
    }
}

// src/Controller/GiftCardOrderController.php
namespace App\Controller;

use Amilon\Dto\Request\CreateOrderRequestDto;
use Amilon\Exception\AmilonExceptionInterface;
use Amilon\Service\AmilonClient;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route;

final class GiftCardOrderController
{
    public function __construct(
        private readonly AmilonClient $amilonClient,
    ) {
    }

    #[Route('/gift-cards/orders', name: 'gift_card_order_create', methods: ['POST'])]
    public function __invoke(Request $request): JsonResponse
    {
        $retailerId = (string) $request->request->get('retailerId');
        $quantity = (int) $request->request->get('quantity', 1);
        $price = (float) $request->request->get('price');
        $externalOrderId = 'order-' . bin2hex(random_bytes(8));

        try {
            $order = $this->amilonClient->makeOrder(
                CreateOrderRequestDto::singleLineWithPrice($externalOrderId, $retailerId, $quantity, $price),
            );
        } catch (AmilonExceptionInterface $amilonExceptionInterface) {
            // InvalidOrderRequestException -> bad input (400);
            // AuthenticationException / ApiRequestException -> upstream failure (502)
            return new JsonResponse(['error' => $amilonExceptionInterface->getMessage()], 502);
        }

        return new JsonResponse([
            'externalOrderId' => $order->externalOrderId,
            'status' => $order->orderStatus,
            'vouchers' => array_map(
                static fn ($voucher): string => $voucher->voucherLink,
                $order->vouchers,
            ),
        ]);
    }
}

Amilon\Dto\Response\MerchantDenominationCollectionDto {
  // iterable + countable: ->all() ->count() ->isEmpty()
  -merchants: array:12 [
    0 => Amilon\Dto\Response\MerchantDenominationsDto {
      +code: "f72c8dc7-8feb-4dad-bf66-39c8ed238a2b"   // <- retailerId for makeOrder()
      +country: "Spain"
      +countryIsoAlpha3: "ESP"
      +name: "Carrefour"
      +shortDescription: "Carrefour es una cadena de distribución multinacional..."
      +longDescription: "<p>Carrefour es una cadena de distribuci&oacute;n...</p>"
      +imageUrl: "https://eurob2b.amilon.eu/b2bfiles/retailers/f72c8dc7-.../logo/a6fd150c.png"
      +slug: "carrefour-esp"
      +currency: "Euro"
      +currencySymbol: "€"
      +rebateTypeName: "Sconto fisso per Retailer"
      +vatValue: 0.0
      +vatValueName: "FC IVA art. 6-quater"
      +denominations: array:7 [
        0 => Amilon\Dto\Response\DenominationDto {
          +code: "911d5af7-419b-ed11-b820-005056a53626"
          +activationDate: DateTimeImmutable @1674497920 { 2023-01-23 18:18:40.0 UTC (+00:00) }
          +imageUrl: "https://eurob2b.amilon.eu/b2bfiles/products/8f42058d-.../logo/d1ded420.png"
          +rangeMin: null
          +rangeMax: null
          +step: null
          +discountValue: 0.01
          +prices: array:1 [
            0 => Amilon\Dto\Response\DenominationPriceDto {
              +price: 20.0
              +netPrice: 19.8
            }
          ]
          +image136x86: ""   +image461x292: ""   +image200x200: ""   +image300x190: ""   +image560x292: ""
          // the image* sizes are "" here — only getDenominationsComplete() fills them
          // isFixed() => true   isVariable() => false   hasContractPriceOverride() => false
        }
        // 6 more fixed denominations: 100.0, 10.0, 25.0, 50.0, 5.0, 150.0
      ]
      +extendedContent: null            // only getDenominationsComplete() fills this
    }
    // 11 more merchants
  ]
}

// isVariable() — open span, empty prices; any multiple of step in [rangeMin, rangeMax] is orderable
Amilon\Dto\Response\DenominationDto {
  +code: "68675d82-979f-f011-aa09-005056841cb3"
  +rangeMin: 5.0
  +rangeMax: 500.0
  +step: 5.0
  +discountValue: 0.02
  +prices: []
}

// hasContractPriceOverride() — no range, an explicit contract-fixed set of values
Amilon\Dto\Response\DenominationDto {
  +code: "68675d82-979f-f011-aa09-005056841cb3"
  +rangeMin: null
  +rangeMax: null
  +step: null
  +discountValue: null
  +prices: array:7 [
    0 => Amilon\Dto\Response\DenominationPriceDto { +price: 5.0  +netPrice: 5.0 }
    1 => Amilon\Dto\Response\DenominationPriceDto { +price: 10.0 +netPrice: 10.0 }
    // 25.0, 50.0, 100.0, 250.0, 500.0
  ]
}

Amilon\Dto\Response\ProductCollectionDto {
  // iterable + countable: ->all() ->count() ->isEmpty()
  -products: array:84 [
    0 => Amilon\Dto\Response\ProductDto {
      +productCode: "911d5af7-419b-ed11-b820-005056a53626"   // denomination code; NOT unique per value
      +merchantCode: "f72c8dc7-8feb-4dad-bf66-39c8ed238a2b"  // == MerchantDenominationsDto->code
      +name: "Carrefour - 20,00 €"                           // synthesised
      +price: 20.0
      +imageUrl: "https://eurob2b.amilon.eu/b2bfiles/products/8f42058d-.../logo/d1ded420.png" // denomination art, merchant-logo fallback
      +active: true                                          // always true
      +visible: true                                         // always true
      +netPrice: 19.8
      +discountValue: 0.01
      +currency: "Euro"
      +currencySymbol: "€"
      +rangeMin: null
      +rangeMax: null
      +step: null
      +activationDate: DateTimeImmutable @1674497920 { 2023-01-23 18:18:40.0 UTC (+00:00) }
      // ── legacy merchant block: copied onto every row from the parent MerchantDenominationsDto,
      //    the same fields V1's product row carried ──
      +merchantName: "Carrefour"
      +countryIsoAlpha3: "ESP"                               // == MerchantCountryISOAlpha3
      +merchantCountry: "Italy"                              // == MerchantCountry
      +merchantImageUrl: "https://eurob2b.amilon.eu/b2bfiles/retailers/f72c8dc7-.../logo/aeab1a64.png" // pure merchant logo
      +merchantShortDescription: "Carrefour, la spesa quotidiana e molto altro."
      +merchantLongDescription: "<p>...</p>"                  // HTML
      +merchantSlug: "carrefour-ita"
      +rebateTypeName: "Sconto fisso per Retailer"
      +vatValue: 0.0                                         // int % as float
      +vatValueName: "FC IVA art. 6-quater"
      +productType: "Voucher"                                // constant (V2 has no product type)
      +art100: false                                         // always false (V2 dropped the flag)
      // isVariablePriced() => false
    }
    // a variable denomination collapses to ONE row: price == rangeMin, rangeMin/rangeMax/step
    // set, netPrice 0.0, isVariablePriced() => true
  ]
}

Amilon\Dto\Response\RetailerCategoryCollectionDto {
  // iterable + countable: ->all() ->count() ->isEmpty()
  -categories: array:2 [
    0 => Amilon\Dto\Response\RetailerCategoryDto {
      +categoryId: "3fa85f64-5717-4562-b3fc-2c963f66afa6"
      +categoryName: "Elettronica"
    }
    1 => Amilon\Dto\Response\RetailerCategoryDto {
      +categoryId: "5ba85f64-5717-4562-b3fc-2c963f66afd2"
      +categoryName: "Libri"
    }
  ]
}