f7fc69077b
- Convert static $modelLabel/$pluralModelLabel/$title to getter methods - Wrap ->label()/->placeholder()/->helperText()/->description()/->title()/->body() args - Wrap Section::make()/Fieldset::make()/Notification::make()->title() args - Fix RelationManagers::getTitle() signature to match parent (Model, string) - Fix Pages::getTitle() to instance method (BasePage::getTitle is non-static) - Extend lang/ru.json + lang/en.json with 700+ common terms; identity fallback for the rest - Remove duplicate getters in 5 resources that had manual getModelLabel already All 306 tests pass. Missing translations fall back to the RO key so the UI never breaks. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
97 lines
3.9 KiB
PHP
97 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Tenant\Resources\PurchaseResource\Pages;
|
|
|
|
use App\Filament\Tenant\Resources\PurchaseResource;
|
|
use App\Models\Tenant\Purchase;
|
|
use App\Models\Tenant\PurchaseItem;
|
|
use App\Models\Tenant\Supplier;
|
|
use App\Services\Ai\OcrInvoiceService;
|
|
use Filament\Actions;
|
|
use Filament\Forms;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Resources\Pages\ListRecords;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class ListPurchases extends ListRecords
|
|
{
|
|
protected static string $resource = PurchaseResource::class;
|
|
|
|
protected function getHeaderActions(): array
|
|
{
|
|
return [
|
|
Actions\Action::make('ocr')
|
|
->label(__('Import factură (OCR)'))
|
|
->icon('heroicon-m-document-arrow-up')
|
|
->color('gray')
|
|
->modalHeading(__('Import factură via OCR'))
|
|
->modalDescription(__('Încarcă o poză cu factura. AI-ul extrage furnizorul, data și liniile. Verifici și salvezi.'))
|
|
->schema([
|
|
Forms\Components\FileUpload::make('invoice')
|
|
->label(__('Foto factură'))
|
|
->image()
|
|
->disk('local')
|
|
->directory('ocr-imports')
|
|
->required()
|
|
->maxSize(5120),
|
|
])
|
|
->action(function (array $data) {
|
|
$abs = Storage::disk('local')->path($data['invoice']);
|
|
$result = app(OcrInvoiceService::class)->extract($abs);
|
|
|
|
if (! ($result['ok'] ?? false)) {
|
|
Notification::make()
|
|
->title(__('OCR eșuat'))
|
|
->body($result['error'] ?? 'Eroare necunoscută.')
|
|
->danger()->send();
|
|
@unlink($abs);
|
|
return;
|
|
}
|
|
|
|
$payload = $result['data'];
|
|
|
|
// Match supplier by case-insensitive name.
|
|
$supplierId = null;
|
|
if ($payload['supplier_name']) {
|
|
$supplierId = Supplier::whereRaw('LOWER(name) = ?', [mb_strtolower($payload['supplier_name'])])
|
|
->value('id');
|
|
}
|
|
|
|
$purchase = Purchase::create([
|
|
'number' => Purchase::generateNumber(
|
|
app(\App\Tenancy\TenantManager::class)->currentId()
|
|
),
|
|
'supplier_id' => $supplierId,
|
|
'order_date' => $payload['date'] ?? today()->toDateString(),
|
|
'status' => 'draft',
|
|
'notes' => 'Importat OCR' . ($payload['supplier_name'] && ! $supplierId
|
|
? " · furnizor nemap-uit: „{$payload['supplier_name']}”"
|
|
: ''),
|
|
]);
|
|
|
|
foreach ($payload['items'] as $item) {
|
|
PurchaseItem::create([
|
|
'purchase_id' => $purchase->id,
|
|
'name' => $item['name'],
|
|
'qty' => $item['qty'],
|
|
'unit' => 'buc',
|
|
'buy_price' => $item['unit_price'],
|
|
]);
|
|
}
|
|
$purchase->refresh()->recalcTotal();
|
|
|
|
@unlink($abs);
|
|
|
|
Notification::make()
|
|
->title(__('Factură importată'))
|
|
->body(sprintf('%d linii, total %.2f. Verifică și ajustează înainte de a confirma.',
|
|
count($payload['items']), (float) $purchase->total))
|
|
->success()->send();
|
|
|
|
$this->redirect(PurchaseResource::getUrl('edit', ['record' => $purchase]));
|
|
}),
|
|
Actions\CreateAction::make(),
|
|
];
|
|
}
|
|
}
|