Frappe ERP:
- findExistingCustomer() on FrappeErpAdapter — two-step name+address lookup
- FrappeHttpClient: add put() method; switch invoice submit to PUT docstatus=1 (Frappe v16)
- buildItemDescription() uses specsText + inventory number + serial number
- Integration tests: find Simon Kühn, create real 1337€ invoice, cancel+delete in tearDown
- FRAPPE_GENERIC_ITEM_CODE=SKU002 added to .env.local and bin/test-integration
Pipeline — model cache:
- PhotoUploadHandler: after vision, check DB for existing article with same modelNumber
- On match: copy ebayTitle/ebayDescription/specsText/attributes, skip specs+JSON+eBay steps
- DraftArticleHandler: apply model_match data and mark job complete directly
- ArticleRepository: findCompletedByModelNumber() query
Pipeline — specs by article type:
- SpecsResearchAgent: accept attributeFields list, format as bullet list in {{fields}} var
- SpecsResearchHandler: derive attribute names from ArticleType, pass to agent
- SpecsResearchMessage: add attributeFields param
- Prompt migration: replace hardcoded laptop spec list with {{fields}} placeholder
Article:
- specsText field (nullable text column + migration)
- stock field visible on index and editable in CRUD form
- addAttributeValue()/removeAttributeValue() adder-remover pair for Symfony form binding
- AttributeValue::getArticle() getter
- AttributeValueFormType: detect required attributes from ArticleType assignments, set required=true
- ManualIngestType: add stock/quantity field (default 1, min 1)
Users / ACL:
- PermissionVoter: define named permission constants + allPermissions()
- User: getGrantedPermissions()/setGrantedPermissions() helpers
- UserCrudController: permissions checkbox group on edit form
UI / assets:
- public/css/admin/custom.css: red asterisk for required fields
- DashboardController: register custom CSS
Infra:
- PipelineJobFailureListener: mark job failed (with real error) when Messenger exhausts retries
- doctrine.yaml: exclude app.inventory_seq from schema diff
- ErpAdapterInterface: add findExistingCustomer()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Photos field moved to first position. ID field removed entirely. eBay
description on detail uses a custom template that renders raw HTML in a
plain div (no span/title wrapper, no overflow constraints). Form view
keeps the textarea editor.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TextField rejects Collection values before formatValue runs. Switching to
the generic Field avoids the type check. ebayDescription now renders its
HTML tags in the detail view instead of showing raw markup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds model_name VARCHAR(255) column to app.articles, exposes it in the
admin CRUD form (optional, hidden on index), and adds translations for
both EN and DE.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add secured GET /admin/photos/{filename} to serve files from var/uploads/
- Add POST /api/articles/{id}/photos/sort for drag-and-drop reordering
- Add PhotoService::reorder() to persist new sort positions
- Add photo gallery field (onlyOnDetail) using custom Twig template:
- Drag-and-drop reorder via SortableJS CDN
- Click or drop to upload new photos
- Set main (★) and delete per photo
- Main photo highlighted with blue border + badge
- Add field.photos translation key (EN/DE)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add hasActiveJobForArticle() to check for queued/processing jobs.
The displayIf closure hides the action while a job is running.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add LocaleSubscriber: detects browser language, honours session override (priority 20)
- Add LocaleSwitchController: stores locale in session, linked from user menu
- Add admin.en.yaml / admin.de.yaml translation files (95 keys each)
- Wire translation fallback to EN in config/packages/translation.yaml
- Replace all hard-coded strings in CRUD controllers with TranslatableMessage
- Inject TranslatorInterface into DashboardController, ArticleCrudController,
AIPipelineJobCrudController and PipelineStreamController; add locale switcher
links (English / Deutsch) to the user menu
- Add confirmation dialog to "Re-run AI" and "Retry" pipeline actions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CRUD controllers for Article, ArticleType, AttributeDefinition,
ArticleTypeAttribute, AIPipelineJob, Order, Customer, Invoice, User
and LogEntry. SecurityController handles login/logout; TotpSetupController
manages 2FA enrollment. API controllers for pipeline and orders.
Admin dashboard template and Twig base layout included.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>