SuperSeller3000/tests/Integration/Infrastructure/Channel/Frappe/FrappeErpAdapterIntegrationTest.php
Simon Kuehn a79791a972
Some checks are pending
CI / test (push) Waiting to run
style: apply CS Fixer formatting across codebase
Consistent brace style, spacing, and method expansion throughout
domain, infrastructure, and test files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 10:56:37 +00:00

138 lines
4.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Integration\Infrastructure\Channel\Frappe;
use App\Domain\Article\Article;
use App\Domain\Article\ArticleCondition;
use App\Domain\Article\ArticleType;
use App\Domain\Channel\Platform;
use App\Domain\Order\Customer;
use App\Domain\Order\Order;
use App\Infrastructure\Channel\Frappe\FrappeErpAdapter;
use App\Infrastructure\Channel\Frappe\FrappeHttpClient;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\HttpClient;
/**
* Integration tests against the live ERPNext staging instance.
* Requires FRAPPE_ERP_BASE_URL, FRAPPE_ERP_API_KEY, FRAPPE_ERP_API_SECRET,
* FRAPPE_GENERIC_ITEM_CODE in .env.local.
*
* Run with: bin/test-integration
*/
final class FrappeErpAdapterIntegrationTest extends TestCase
{
private FrappeErpAdapter $adapter;
private FrappeHttpClient $client;
private string $createdInvoiceName = '';
protected function setUp(): void
{
$baseUrl = $_SERVER['FRAPPE_ERP_BASE_URL'] ?? getenv('FRAPPE_ERP_BASE_URL');
$apiKey = $_SERVER['FRAPPE_ERP_API_KEY'] ?? getenv('FRAPPE_ERP_API_KEY');
$apiSecret = $_SERVER['FRAPPE_ERP_API_SECRET'] ?? getenv('FRAPPE_ERP_API_SECRET');
$itemCode = $_SERVER['FRAPPE_GENERIC_ITEM_CODE'] ?? getenv('FRAPPE_GENERIC_ITEM_CODE');
if (!$baseUrl || !$apiKey || !$apiSecret || !$itemCode) {
$this->markTestSkipped('FRAPPE_ERP_* env vars not set');
}
$this->client = new FrappeHttpClient(
HttpClient::create(),
(string) $baseUrl,
(string) $apiKey,
(string) $apiSecret,
);
$this->adapter = new FrappeErpAdapter($this->client, (string) $itemCode);
}
protected function tearDown(): void
{
if ('' !== $this->createdInvoiceName) {
try {
$this->client->put('/api/resource/Sales Invoice/'.$this->createdInvoiceName, ['docstatus' => 2]);
$this->client->delete('/api/resource/Sales Invoice/'.$this->createdInvoiceName);
} catch (\Throwable) {
// best-effort cleanup
}
}
}
public function testFindSimonKuehnByNameAndAddress(): void
{
$customerId = $this->adapter->findExistingCustomer(
'Simon Kühn',
'Kirchstr. 1',
'Karbach',
'56281',
);
$this->assertNotNull($customerId, 'Simon Kühn should exist in Frappe staging');
$this->assertStringStartsWith('Simon', $customerId);
}
public function testUnknownPersonIsNotFound(): void
{
$customerId = $this->adapter->findExistingCustomer(
'Voldemort',
'Dunkle Gasse 1',
'Nirgendwo',
'00000',
);
$this->assertNull($customerId);
}
public function testFindSimonAndCreateInvoiceFor1337(): void
{
$frappeId = $this->adapter->findExistingCustomer(
'Simon Kühn',
'Kirchstr. 1',
'Karbach',
'56281',
);
$this->assertNotNull($frappeId, 'Simon Kühn should exist in Frappe staging');
$simon = new Customer('Simon Kühn', 'simon.kuehn83@gmail.com', [
'street' => 'Kirchstr. 1',
'city' => 'Karbach',
'zip' => '56281',
]);
$simon->setFrappeCustomerId($frappeId);
$article = new Article(
new ArticleType('Laptop'),
'LAP-THINK-SIMON',
'INV-THINK-SIMON',
1,
ArticleCondition::Good,
);
$article->setManufacturer('Lenovo');
$article->setModelName('ThinkBook 14 G6 IRL');
$article->setModelNumber('21KG00NQGE');
$article->setSerialNumber('PNV09SJZ');
$article->setEbayTitle('Lenovo ThinkBook 14 G6 IRL — generalüberholt, läuft wie Butter');
$order = new Order(
$article,
$simon,
new Platform('direct', 'Direktverkauf'),
'ORDER-SIMON-1337',
'1337.00',
new \DateTimeImmutable('2026-05-18'),
);
$invoiceId = $this->adapter->createSalesInvoice($order);
$this->assertNotEmpty($invoiceId);
$this->createdInvoiceName = $invoiceId;
// Verify the invoice actually exists in Frappe
$response = $this->client->get('/api/resource/Sales Invoice/'.$invoiceId);
$this->assertSame($invoiceId, $response['data']['name']);
$this->assertEquals(1337.0, $response['data']['grand_total']);
}
}