arturas88/finvalda-sdk
A PHP SDK for integrating Finvalda accounting and business management services into Laravel applications. It provides a structured client for API authentication, data retrieval, and common Finvalda operations, simplifying financial system integration.
arturas88/finvalda-sdk) and configure Finvalda credentials per package docs. As of v3.4.0 the SDK is PHPStan level 5 clean with 297 tests, so the test suite is a reliable first reference.PurchaseBuilder, PurchaseOrderBuilder, ProductLine, Stock, and the new purchaseUpdate() path. The v3.4.0 tests around additional costs, corrections, and stock lookup are the fastest way to learn intended usage.$finvalda->purchase()
->client('SUP001')
->additionalCostCodes(['KITOS', 'TRANSP', 'ILGALSAV', 'DRAUDIM'])
->product(
ProductLine::make('WSM000001TB061527', 1)
->warehouse('WH01')
->amount(38_500.00)
->additionalCost(2, 950.00) // TRANSP -> dPapIsldSumaV2/L2
)
->save('PIRKNAU');
Stock::purchaseOpFor($productCode) as a pre-flight check. It answers whether the product is still held by a purchase operation and whether it has been sold since.additionalCostCodes() and line amounts with ProductLine::additionalCost() or additionalCosts(). The slot number is the binding key between the two.additionalCostCodes([2 => 'TRANSP']). Use ordered lists only when the slot order is obvious and stable.ProductLine::additionalCosts([1 => 10.00, 2 => 950.00]) for multi-bucket lines. The helper writes both dPapIsldSumaV{slot} and dPapIsldSumaL{slot} as a pair, avoiding the half-pair mistake that set() made easy.purchaseUpdate() as a delete-and-re-add operation, not an edit. Build the KoregPirkDok envelope through the SDK rather than hand-assembling it.$op = $finvalda->stock()->purchaseOpFor('WSM000001TB061527');
if ($op === null || ($op['sold'] ?? false)) {
// do not correct; inspect history or choose another action
}
$finvalda->purchaseUpdate()
->assertNotSold(['WSM000001TB061527'])
->header(/* ... */)
->product(/* replacement detail lines */)
->save(/* ... */);
save() to call assertNotSold(). The SDK deliberately leaves that decision to the caller because it costs one round trip per product code and is a business decision, not a serialization concern.UpdateOperationClass cases, use operations()->update() with a hand-built payload. v3.4.0 only adds a first-class purchase correction builder.4027 explicitly. An update call can return a deletion-class code because the correction path deletes detail lines internally.Stock::purchaseOpFor() as a read-only pre-flight, not as a transactional lock. It returns a plain array and never throws, so callers must branch on null and on the reported sold state.build() time.additionalCostCodes() is rejected on ->short() at build() time because TrumpasPirkDok/TrumpasPirkUzsDok have no such fields. It is also absent from purchaseReturn() per the spec.ProductLine::additionalCost() and additionalCosts() write both the currency and local amount fields. Do not use raw set() calls for these fields; a half-populated pair books the line incorrectly.ServiceLine. The spec marks all eight fields as Tik PirkDokPrekeDetEil, so service lines cannot carry them.4027 (Operacijos detalios eilutės yra panaudotos kitose operacijose!) comes from the internal delete, not from the 5000–5005 correction family. Do not assume an update call can only return correction-class errors.UpdPrekeDetEil is not an escape hatch for restating amounts. It carries only nPozymis and sPapInfo.purchaseUpdate()->header() refuses fields the PirkDokHeadEil node does not accept for a purchase: sKlientas (supplier cannot change), operation-date fields, sObjektas5/6, and waybill fields.assertNotSold() fails closed on unresolvable history. That is safer than correcting blindly, but it means a lookup failure blocks the correction until you investigate.Stock::purchaseOpFor() returns null for no purchase history or a failed call, and never throws. It is a pre-flight check, not a source of truth for accounting decisions.op_rusis_pav values Pirkimai and Pardavimai are observed against a live Finvalda, not documented in the API spec. Unknown kinds are ignored rather than guessed, so do not assume every history row will be classified.Tik ... annotations; use the generic operations()->update() path with a hand-built payload.build() time, so validation errors usually point to the exact field or arity problem.How can I help you explore Laravel packages today?