1. Go to this page and download the library: Download arturas88/finvalda-sdk 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/ */
arturas88 / finvalda-sdk example snippets
use Finvalda\Finvalda;
use Finvalda\FinvaldaConfig;
// Configure the client
$config = new FinvaldaConfig(
baseUrl: 'https://your-server.com/FvsServicePure.svc',
username: 'your-username',
password: 'your-password',
);
$finvalda = new Finvalda($config);
// Test connection
if (! $finvalda->ping()) {
die('Connection failed — check credentials and server URL');
}
// Fetch all clients as a typed collection
$clients = $finvalda->clients()->collect();
foreach ($clients as $client) {
echo "{$client->code}: {$client->name}\n";
}
// Create a sale using the fluent builder
$result = $finvalda->sale()
->client('CLI001')
->date('2024-01-15')
->warehouse('MAIN')
->addProduct('PRD001', quantity: 10, price: 19.99)
->addProduct('PRD002', quantity: 5, amount: 49.95)
->save('STANDARD');
if ($result->success) {
echo "Created: {$result->journal} #{$result->number}";
}
use Finvalda\Finvalda;
use Finvalda\FinvaldaConfig;
use Finvalda\Enums\Language;
use Finvalda\Enums\CredentialMode;
use Finvalda\Retry\RetryPolicy;
$config = new FinvaldaConfig(
baseUrl: 'https://your-server.com/FvsServicePure.svc',
username: 'your-username',
password: 'your-password',
// Optional parameters:
connString: null, // Database connection string
companyId: null, // Company ID for multi-database setups
language: Language::Lithuanian, // or Language::English
removeEmptyStringTags: false,
removeZeroNumberTags: false,
removeNewLines: false,
timeout: 30,
logger: null, // PSR-3 logger instance
retry: null, // RetryPolicy instance
record: false, // Keep the last N exchanges in memory
recordLimit: 20,
recordCredentials: CredentialMode::Masked, // or Env (placeholders) / Real
);
$finvalda = new Finvalda($config);
// Dependency injection
public function index(Finvalda\Finvalda $finvalda)
{
$clients = $finvalda->clients()->collect();
}
// Facade
use Finvalda\Laravel\Facades\Finvalda;
$clients = Finvalda::clients()->collect();
// Render a template that exists only on the default company (no CompanyID header)
// for a document created under this client's company.
$pdf = $finvalda->withoutCompany()->reports()->makeInvoicePdf($params);
// Or target another company explicitly.
$clients = $finvalda->withCompany('HTNT')->clients()->collect();
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// Create a logger
$logger = new Logger('finvalda');
$logger->pushHandler(new StreamHandler('path/to/finvalda.log', Logger::DEBUG));
// Option 1: Pass in config
$config = new FinvaldaConfig(
// ...
logger: $logger,
);
// Option 2: Set after initialization
$finvalda->setLogger($logger);
$config = new FinvaldaConfig(
// ...
logFileContents: false, // default — set true to log payloads verbatim
logBodyBytes: 100_000, // byte budget for what is left after eliding
);
use Finvalda\Logging\JsonLinesLogger;
$config = new FinvaldaConfig(
// ...
logger: new JsonLinesLogger('/var/log/finvalda/finvalda.log'),
);
$finvalda->setDebug(true);
// Make any API call
$result = $finvalda->operations()->create(OperationClass::Sale, $data, 'PARAM');
// Inspect what was sent and received
$debug = $finvalda->getLastDebugInfo();
print_r($debug['request']); // method, url, headers, body
print_r($debug['response']); // status_code, headers, body
// Disable debug mode (clears stored info)
$finvalda->setDebug(false);
use Finvalda\Enums\CredentialMode;
$finvalda->record(); // last 20 exchanges, credentials masked
$finvalda->record(limit: 5);
$finvalda->record(credentials: CredentialMode::Env); // $FVS_PASSWORD placeholders
$finvalda->record(credentials: CredentialMode::Real); // real credentials
$finvalda->sale()->client('C001')->save('PARD');
echo $finvalda->lastRecording(); // formatted HTTP text
echo $finvalda->lastRecording()->toCurl(); // curl command
foreach ($finvalda->recordings() as $exchange) {
echo $exchange->toCurl(), PHP_EOL;
}
$finvalda->stopRecording(); // stops and drops the buffer
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
$mock = new MockHandler([
new Response(200, [], json_encode(['AccessResult' => 'Success', 'items' => []])),
]);
$httpClient = new \Finvalda\HttpClient($config, new Client(['handler' => HandlerStack::create($mock)]));
$finvalda = new Finvalda($config, $httpClient);
use Finvalda\Data\Client;
use Finvalda\Data\Product;
use Finvalda\Data\Service;
use Finvalda\Exceptions\NotFoundException;
// Find a client - returns typed Client DTO
$client = $finvalda->clients()->find('CLI001');
echo $client->name; // Full IDE autocomplete
echo $client->email;
echo $client->vatCode;
echo $client->debt;
// Find a product
$product = $finvalda->products()->find('PRD001');
echo $product->name;
echo $product->price1;
echo $product->barcode;
echo $product->supplier1;
// Find a service
$service = $finvalda->services()->find('SVC001');
echo $service->name;
echo $service->price;
// Handle not found
try {
$client = $finvalda->clients()->find('NONEXISTENT');
} catch (NotFoundException $e) {
echo "Client not found";
}
// Access raw API data if needed
$rawData = $client->raw;
$specificField = $client['sSpecialField']; // ArrayAccess supported
use Finvalda\Collections\ClientCollection;
use Finvalda\Collections\ProductCollection;
// Get all clients as a typed collection
$clients = $finvalda->clients()->collect();
// Filter clients with debt
$debtors = $clients->withDebt();
$totalDebt = $clients->totalDebt();
// Filter by type
$vipClients = $clients->whereType('VIP');
// Find by code within collection
$client = $clients->findByCode('CLI001');
// Get products
$products = $finvalda->products()->collect();
// Filter by type
$electronics = $products->whereType('ELECTRONICS');
// Filter by supplier
$fromSupplier = $products->whereSupplier('SUP001');
// Products with stock
$inStock = $products->withStock();
// Filter by tag
$tagged = $products->whereTag(1, 'FEATURED');
// Find by barcode
$product = $products->findByBarcode('1234567890123');
// Collection methods work on all collections
$clients->count(); // Count items
$clients->isEmpty(); // Check if empty
$clients->isNotEmpty(); // Check if not empty
$clients->first(); // Get first item
$clients->last(); // Get last item
$clients->get(5); // Get by index
$clients->all(); // Get as array
// Filtering and mapping
$filtered = $clients->filter(fn($c) => $c->debt > 1000);
$names = $clients->map(fn($c) => $c->name);
$codes = $clients->pluck('code');
// Iteration
foreach ($clients as $client) {
echo "{$client->code}: {$client->name}\n";
}
// Execute callback for each
$clients->each(function($client) {
sendReminder($client);
});
// Group by field
$byType = $clients->groupBy(fn($c) => $c->type);
foreach ($byType as $type => $typeClients) {
echo "{$type}: {$typeClients->count()} clients\n";
}
// Convert to array
$array = $clients->toArray();
// Date filtering
$recentClients = $finvalda->clients()->collect(modifiedSince: '2024-01-01');
$newProducts = $finvalda->products()->collect(createdSince: '2024-06-01');
// Product (default, first measurement): qty sent verbatim in the primary unit
$finvalda->sale()->client('CLI001')->product(
ProductLine::make('1141817', 250.0) // nKiekis = 250, nPirmasMat = 1 → 250 m
)->save('STANDARD');
// Product, second measurement: Finvalda rescales by the unit ratio (rarely what you want)
$finvalda->sale()->client('CLI001')->product(
ProductLine::make('1141817', 250.0)->secondMeasurement() // nKiekis = 250 → 2.5 m on an "M" product
)->save('STANDARD');
// Service, second measurement (default): qty 1 → nKiekis 100, 0.5 → 50
$finvalda->sale()->client('CLI001')->service(
ServiceLine::make('TRANSPORT', 0.5) // nKiekis = 50
)->save('STANDARD');
// Service, first measurement: qty sent as-is
$finvalda->sale()->client('CLI001')->service(
ServiceLine::make('TRANSPORT', 1)->firstMeasurement() // nKiekis = 1, nPirmasMat = 1
)->save('STANDARD');
$stock = $finvalda->stock()->purchaseOpFor('WSM000001TB061527');
if ($stock === null || $stock['sold']) {
// Sold, or never purchased. A correction here would hit 4027, or rebuild a
// stock layer underneath a sale. Report it; let an accountant handle it.
return;
}
$finvalda->purchaseUpdate()
->journal($stock['journal'])
->number($stock['op_number'])
->additionalCostCodes([2 => 'TRANSP'])
->removeProduct('WSM000001TB061527', $stock['warehouse'])
->product(
ProductLine::make('WSM000001TB061527', 1)
->warehouse($stock['warehouse'])
->amount(38_500.00)
->vat(percent: 21, amount: 8_085.00)
->additionalCost(2, 1_270.00) // was 950.00
)
->save('PIRKNAU');
// Short sale — server applies default settings
$result = $finvalda->sale()
->short()
->client('CLI001')
->date('2024-01-15')
->series('SF')
->currency('EUR')
->addProduct('PRD001', quantity: 10, price: 19.99)
->save('STANDARD');
// Short purchase return
$result = $finvalda->purchaseReturn()
->short()
->client('SUP001')
->currency('EUR')
->series('GR')
->addProduct('PRD001', quantity: 10, price: 9.99)
->save('RETURN');
use Finvalda\Query\TransactionQuery;
// Create a fluent query
$query = TransactionQuery::create()
->journal('PARD')
->series('AA')
->dateRange('2024-01-01', '2024-12-31')
->modifiedSince('2024-06-01');
// Use with transactions resource
$response = $finvalda->transactions()->sales($query->toFilter());
$response = $finvalda->transactions()->salesDetail($query->toFilter());
// Query methods
$query = TransactionQuery::create()
->journal('PARD') // Filter by journal code
->operationNumber(123) // Filter by operation number
->series('AA') // Filter by document series
->orderNumber('SF-001') // Filter by order/document number
->journalGroup('SALES_GRP') // Filter by journal group
->dateFrom('2024-01-01') // Operation date from
->dateTo('2024-12-31') // Operation date to
->dateRange('2024-01-01', '2024-12-31') // Both dates at once
->modifiedSince('2024-06-01'); // Only modified since
$op = $finvalda->stock()->purchaseOpFor('WSM000001TB061527');
if ($op === null) {
// never purchased, or the history call failed
} elseif ($op['sold']) {
// sold on $op['sale_date'] via $op['sale_journal'] #$op['sale_op_number']
} else {
// current layer: $op['journal'] #$op['op_number'], warehouse $op['warehouse']
}
[
'journal' => 'PIRKNAU', 'op_number' => 1421, 'warehouse' => 'WH01',
'op_date' => '2026-07-01',
'sold' => true, 'sale_journal' => 'PARD1', 'sale_op_number' => 77,
'sale_date' => '2026-07-20', // sale_* are null when sold is false
]
use Finvalda\Enums\ClientTypeId;
// List / find / collect
$response = $finvalda->clients()->list();
$response = $finvalda->clients()->list(modifiedSince: '2024-01-01');
$response = $finvalda->clients()->get('CLIENT001');
$client = $finvalda->clients()->find('CLIENT001'); // Returns typed Client DTO
$clients = $finvalda->clients()->collect(); // Returns ClientCollection
// All clients (with optional date filters)
$response = $finvalda->clients()->all();
$response = $finvalda->clients()->all(modifiedSince: '2024-01-01');
// Find client by email
$response = $finvalda->clients()->findByEmail('[email protected]');
// Client types and tags — see "Types and tags" below for how this works
$types = $finvalda->clients()->typesAndTags(ClientTypeId::Type); // TypeTagCollection of client types
$tag1 = $finvalda->clients()->typesAndTags(ClientTypeId::Tag1); // Tag 1 options
$all = $finvalda->clients()->allTypesAndTags(); // whole dictionary in one call
// Clients by type
$response = $finvalda->clients()->byType('VIP');
// Accounts (with full filter support)
$response = $finvalda->clients()->accounts(clientCode: 'CLIENT001');
$response = $finvalda->clients()->accounts(
clientCode: 'CLIENT001',
journalGroup: 'PARD',
debtType: 1,
documentDateFrom: '2024-01-01',
documentDateTo: '2024-12-31',
);
// Unpaid documents (sales and purchases)
$response = $finvalda->clients()->unpaidDocuments('CLIENT001');
$response = $finvalda->clients()->unpaidPurchaseDocuments('CLIENT001');
// Client debt condition
$response = $finvalda->clients()->debtCondition('CLIENT001', journalGroup: 'PARD');
// Settlements
$response = $finvalda->clients()->settlements(series: 'SER', document: 'DOC001');
$response = $finvalda->clients()->settlements(journal: 'PARD', number: 123);
$response = $finvalda->clients()->settlementsDetailed(series: 'SER', document: 'DOC001');
$response = $finvalda->clients()->settlementsFromDate(series: 'SER', modifiedSince: '2024-01-01');
$response = $finvalda->clients()->settlementsFromDateParam($xmlParam); // raw XML param variant
// CRUD operations
$result = $finvalda->clients()->create([
'sKodas' => 'NEW001',
'sPavadinimas' => 'New Client Ltd',
'sDebtSask' => '2410',
'sKredSask' => '5001',
]);
$result = $finvalda->clients()->update([
'sKodas' => 'NEW001',
'sPavadinimas' => 'Updated Client Name',
]);
$result = $finvalda->clients()->delete('CLIENT001');
// Invoices related to a customer
$response = $finvalda->clients()->invoicesRelatedToCustomer('CLIENT001', debtType: 0);
use Finvalda\Enums\ProductTypeId;
// List / find / collect
$response = $finvalda->products()->list();
$response = $finvalda->products()->get('PROD001');
$product = $finvalda->products()->find('PROD001'); // Returns typed Product DTO
$products = $finvalda->products()->collect(); // Returns ProductCollection
// Extended list with filters
$response = $finvalda->products()->listExtended(
type: 'ELECTRONICS',
supplier1: 'SUPP01',
modifiedSince: '2024-01-01',
);
// All products
$response = $finvalda->products()->all(modifiedSince: '2024-01-01');
// Product image (envelope with base64 `fileContents`)
$response = $finvalda->products()->image('PROD001');
// Product image as decoded JPG bytes
$jpg = $finvalda->products()->imageJpeg('PROD001');
// Products in warehouse
$response = $finvalda->products()->inWarehouse('WH01', modifiedSince: '2024-01-01');
$response = $finvalda->products()->inWarehouseOrdered('WH01', order: 1);
// Types and tags — see "Types and tags" below for how this works
$types = $finvalda->products()->typesAndTags(ProductTypeId::Type); // TypeTagCollection of product types
$tag1 = $finvalda->products()->typesAndTags(ProductTypeId::Tag1); // Tag 1 options
$all = $finvalda->products()->allTypesAndTags(); // whole dictionary in one call
$response = $finvalda->products()->typeGroups();
$response = $finvalda->products()->typeGroupComposition('GRP01');
$response = $finvalda->products()->byType('ELECTRONICS');
// Product history
$response = $finvalda->products()->history('PROD001', dateFrom: '2024-01-01');
// Sold products per period
$response = $finvalda->products()->soldPerPeriod(
productCode: 'PROD001',
warehouseCode: 'WH01',
dateFrom: '2024-01-01',
dateTo: '2024-12-31',
);
// CRUD operations
$result = $finvalda->products()->create([
'sKodas' => 'NEWPROD',
'sPavadinimas' => 'New Product',
'sRysysSuSask' => '2414',
'sMatavimoVnt' => 'vnt',
]);
$result = $finvalda->products()->update([
'sKodas' => 'PROD001',
'sPavadinimas' => 'Updated Product Name',
]);
// Bulk edit product properties (applies to multiple products at once)
$result = $finvalda->products()->editProperties([
'Kodas' => ['PROD001', 'PROD002', 'PROD003'],
'pardKaina1' => '19.99',
'pardVal' => 'EUR',
]);
$result = $finvalda->products()->delete('PROD001');
use Finvalda\Enums\ServiceTypeId;
// List / find / collect
$response = $finvalda->services()->list();
$response = $finvalda->services()->get('SVC001');
$service = $finvalda->services()->find('SVC001'); // Returns typed Service DTO
$services = $finvalda->services()->collect(); // Returns ServiceCollection
// All services
$response = $finvalda->services()->all(modifiedSince: '2024-01-01');
// Types and tags — see "Types and tags" below for how this works
$types = $finvalda->services()->typesAndTags(ServiceTypeId::Type); // TypeTagCollection of service types
$tag1 = $finvalda->services()->typesAndTags(ServiceTypeId::Tag1); // Tag 1 options
$all = $finvalda->services()->allTypesAndTags(); // whole dictionary in one call
$response = $finvalda->services()->byType('CONSULTING');
// CRUD operations
$result = $finvalda->services()->create([
'sKodas' => 'NEWSVC',
'sPavadinimas' => 'New Service',
'sRysysSuSask' => '5001',
]);
$result = $finvalda->services()->update(['sKodas' => 'SVC001', 'sPavadinimas' => 'Updated']);
$result = $finvalda->services()->delete('SVC001');
use Finvalda\Enums\ProductTypeId;
// A single type/tag group, filtered by tipas → TypeTagCollection of TypeTag
$types = $finvalda->products()->typesAndTags(ProductTypeId::Type);
foreach ($types as $t) {
echo "{$t->code}: {$t->name}\n"; // ->tipas, ->code, ->name, ->info1, ->info2
}
// Raw int works for server-defined tipas without an enum case
$taxable = $finvalda->products()->typesAndTags(100);
// The WHOLE dictionary in ONE HTTP call (cached on the resource instance)
$all = $finvalda->products()->allTypesAndTags(); // TypeTagCollection (every row)
$byTipas = $all->groupByType(); // array<int, TypeTagCollection>
$tag1Values = $byTipas[1] ?? new \Finvalda\Collections\TypeTagCollection();
$present = $all->types(); // distinct tipas values present
// Create a product type (Fvs.PrekesRusis) and a Tag-N value (Fvs.PrekesPoz{N}, N = 1..20)
$finvalda->references()->createProductType(['sKodas' => 'ELECTRONICS', 'sPavadinimas' => 'Electronics']);
$finvalda->references()->createProductTag(1, ['sKodas' => 'PROMO', 'sPavadinimas' => 'Promotional']);
$finvalda->references()->updateProductTag(1, ['sKodas' => 'PROMO', 'sPavadinimas' => 'Promo 2026']);
$finvalda->references()->deleteProductTag(1, 'PROMO');
// Clients: createClientType()/createClientTag(1..3) (Fvs.KlientoRusis / Fvs.Kliento{I|II|III}Poz),
// plus update*/delete* counterparts. Service types/tags are read-only (no API write class).
$finvalda->products()->create([
'sKodas' => 'NEWPROD',
'sPavadinimas'=> 'New Product',
'sRusis' => 'ELECTRONICS', // a Type kodas (tipas 0)
'sPozymis1' => 'PROMO', // a Tag1 kodas (tipas 1)
]);
use Finvalda\Pagination\Cursor;
use Finvalda\Pagination\LazyCollection;
// Create a cursor for clients
$cursor = new Cursor(
fetcher: fn($modifiedSince, $createdSince) =>
$finvalda->clients()->all($modifiedSince, $createdSince)->data,
dateExtractor: fn($item) => isset($item['tKoregavimoData'])
? new \DateTime($item['tKoregavimoData'])
: null,
// Recommended: a stable identity per record so duplicates from
// overlapping date ranges are skipped reliably. Without it, items
// are compared by full content.
idExtractor: fn($item) => $item['sKodas'],
);
// Iterate lazily (memory efficient)
foreach ($cursor->modifiedSince('2024-01-01')->getIterator() as $clientData) {
echo $clientData['sPavadinimas'] . "\n";
}
// Take first N items
$first100 = $cursor->take(100);
// Get all as array
$allClients = $cursor->all();
// LazyCollection for generator-based iteration
$lazy = LazyCollection::make($finvalda->clients()->all()->data);
$filtered = $lazy
->filter(fn($c) => ($c['dSkola'] ?? 0) > 0)
->map(fn($c) => $c['sPavadinimas'])
->take(10)
->all();
use Finvalda\Exceptions\FinvaldaException;
use Finvalda\Exceptions\AccessDeniedException;
use Finvalda\Exceptions\ValidationException;
use Finvalda\Exceptions\NotFoundException;
use Finvalda\Exceptions\NetworkException;
use Finvalda\Exceptions\ServerException;
use Finvalda\Exceptions\RetryExhaustedException;
try {
$client = $finvalda->clients()->find('CLI001');
} catch (NotFoundException $e) {
echo "Client not found";
} catch (AccessDeniedException $e) {
echo "Access denied: {$e->getMessage()}";
} catch (NetworkException $e) {
echo "Network error (connection failed, timeout): {$e->getMessage()}";
} catch (ServerException $e) {
echo "Server error (5xx): {$e->getMessage()}";
} catch (RetryExhaustedException $e) {
echo "All {$e->attempts} retry attempts failed: {$e->getMessage()}";
} catch (ValidationException $e) {
$errors = $e->getErrors();
$allMessages = $e->getAllErrors();
} catch (FinvaldaException $e) {
echo "API error: {$e->getMessage()}";
}
// Check response status
$response = $finvalda->clients()->list();
if ($response->failed()) {
echo "Error: {$response->error}";
}
// Check operation result
$result = $finvalda->clients()->create($data);
if ($result->success) {
echo "Created: {$result->journal} #{$result->number}";
} else {
echo "Error #{$result->errorCode}: {$result->error}";
}
$parameter = 'STANDARD'; // Your server-configured value
$result = $finvalda->operations()->create(OperationClass::Sale, $data, $parameter);
$result = $finvalda->sale()->client('CLI001')->addProduct('PRD001', 10, 19.99)->save($parameter);