Aufräumpunkt k (Spec §31): - Aufbewahrung: services/lotse/retention.ts leert input/output und createdById von AiGeneration-Einträgen älter als AI_GENERATION_RETENTION_DAYS (Default 180), Metadaten bleiben, Audit je Mandant. Queue/Processor ai-retention, täglicher BullMQ-Job-Scheduler beim Start des craftvia-worker. - Kontingent: services/lotse/budget.ts (Tokens ein+aus je Kalendermonat, TenantSettings-Wert vor Env AI_MONTHLY_TOKEN_LIMIT, 0 = unbegrenzt). Lotse-Entwurf und Sprachnotiz-Zusammenfassung → blocked budget_exceeded mit Klartext; Import-Extraktion fällt auf manuelle Erfassung zurück (Hinweis ai_budget_exceeded). /settings/lotse: Kontingent setzen, Verbrauch anzeigen. - scripts/test-betrieb-audit.ts: Audit nach Commit/Rollback/verschachtelt, Merge atomar und in äußerer Transaktion, Audit „read", Aufbewahrung (Frist, Metadaten, Idempotenz, Mandant B), Kontingent (Mandant/Env/Vormonat/unbegrenzt, Rollen, Audit). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
211 lines
7.9 KiB
JSON
211 lines
7.9 KiB
JSON
{
|
||
"crumb": "Work orders",
|
||
"title": "Order import",
|
||
"sub": "Upload an order confirmation, check the recognised data and create the work order. Nothing is created without confirmation.",
|
||
"noPermission": "You are not allowed to import orders.",
|
||
"upload": {
|
||
"title": "Upload document",
|
||
"drop": "Drop a PDF, JPG or PNG here",
|
||
"or": "or",
|
||
"choose": "Choose file",
|
||
"limits": "PDF up to 25 MB, images up to 15 MB. The original stays attached to the work order.",
|
||
"uploading": "Uploading … {percent} %",
|
||
"done": "Uploaded. Recognising data.",
|
||
"errors": {
|
||
"file_type_not_allowed": "File type not allowed. Allowed: PDF, JPG and PNG.",
|
||
"file_too_large": "File is too large.",
|
||
"file_type_mismatch": "File content does not match its type.",
|
||
"file_empty": "File is empty.",
|
||
"file_missing": "No file selected.",
|
||
"forbidden": "Not allowed.",
|
||
"unauthorized": "Session expired. Please sign in again.",
|
||
"network": "Upload failed. Check the connection.",
|
||
"error": "Upload failed."
|
||
}
|
||
},
|
||
"list": {
|
||
"title": "Imports",
|
||
"empty": "No imports yet. Upload an order confirmation.",
|
||
"file": "File",
|
||
"uploadedAt": "Uploaded",
|
||
"uploadedBy": "By",
|
||
"status": "Status",
|
||
"action": "Action",
|
||
"review": "Review",
|
||
"open": "View",
|
||
"workOrder": "Work order {number}"
|
||
},
|
||
"status": {
|
||
"uploaded": "Uploaded",
|
||
"processing": "Processing",
|
||
"review_required": "Review required",
|
||
"confirmed": "Confirmed",
|
||
"failed": "Failed",
|
||
"discarded": "Discarded"
|
||
},
|
||
"actions": {
|
||
"retry": "Process again",
|
||
"retrying": "Starting …",
|
||
"discard": "Discard",
|
||
"discardConfirm": "Discard this import? No work order will be created. The original document is kept.",
|
||
"confirm": "Confirm and create work order",
|
||
"confirming": "Creating work order …"
|
||
},
|
||
"detail": {
|
||
"back": "Back to imports",
|
||
"meta": "{file} · uploaded on {date} by {user}",
|
||
"model": "Recognised with {model}",
|
||
"preview": "Original document",
|
||
"previewTitle": "Preview of the original document",
|
||
"openNewTab": "Open in new tab",
|
||
"download": "Download",
|
||
"processing": "The document is being processed. This page refreshes automatically.",
|
||
"failed": "Processing failed.",
|
||
"failedDetail": "Technical detail: {message}",
|
||
"confirmed": "Import confirmed. Work order {number} was created.",
|
||
"openWorkOrder": "Open work order",
|
||
"corrections": "{count, plural, =0 {No corrections} one {1 field corrected} other {# fields corrected}}",
|
||
"discarded": "Import discarded. No work order was created.",
|
||
"extractedText": "Recognised text",
|
||
"noText": "No text recognised."
|
||
},
|
||
"review": {
|
||
"title": "Check recognised data",
|
||
"intro": "Uncertain fields are marked. Please check and correct them if needed.",
|
||
"manualEntry": "Automatic recognition is not available. Please enter the data manually.",
|
||
"hintsTitle": "Plausibility notes",
|
||
"uncertain": "uncertain",
|
||
"confidence": "Confidence {percent} %",
|
||
"source": "Source: {text}",
|
||
"required": "Required",
|
||
"sections": {
|
||
"customer": "Customer",
|
||
"site": "Site",
|
||
"contact": "Contact person",
|
||
"order": "Work order",
|
||
"positions": "Line items and material"
|
||
},
|
||
"customer": {
|
||
"existing": "Use existing customer",
|
||
"new": "Create new customer",
|
||
"candidates": "Possible matches",
|
||
"noCandidates": "No matching customers found.",
|
||
"match": "Match {percent} %",
|
||
"merge": "Merge duplicates in customer records",
|
||
"search": "Search customers",
|
||
"searchPlaceholder": "Name, customer number or city",
|
||
"searchButton": "Search",
|
||
"searchEmpty": "No customers found.",
|
||
"select": "Select"
|
||
},
|
||
"site": {
|
||
"none": "No site",
|
||
"existing": "Use existing site",
|
||
"new": "Create new site",
|
||
"noSites": "The selected customer has no sites.",
|
||
"chooseCustomer": "Select an existing customer first.",
|
||
"suggested": "Same address"
|
||
},
|
||
"reasons": {
|
||
"customer_number": "customer number",
|
||
"company_name": "company name",
|
||
"company_name_similar": "similar company name",
|
||
"person_name": "name",
|
||
"email": "e-mail",
|
||
"phone": "phone",
|
||
"address": "address",
|
||
"house_number": "house number",
|
||
"site_name": "site name"
|
||
},
|
||
"fields": {
|
||
"customerNumber": "Customer number",
|
||
"companyName": "Company name",
|
||
"firstName": "First name",
|
||
"lastName": "Last name",
|
||
"street": "Street",
|
||
"houseNumber": "House number",
|
||
"postalCode": "Postal code",
|
||
"city": "City",
|
||
"country": "Country",
|
||
"phone": "Phone",
|
||
"email": "E-mail",
|
||
"name": "Name",
|
||
"siteName": "Site name",
|
||
"title": "Work order title",
|
||
"externalOrderNumber": "Order number (document)",
|
||
"offerNumber": "Offer number",
|
||
"description": "Description of services",
|
||
"plannedStart": "Planned start",
|
||
"plannedEnd": "Planned end",
|
||
"notes": "Special notes"
|
||
},
|
||
"extractionFields": {
|
||
"orderNumber": "Order number",
|
||
"offerNumber": "Offer number",
|
||
"customerNumber": "Customer number",
|
||
"companyName": "Company name",
|
||
"customerFirstName": "First name",
|
||
"customerLastName": "Last name",
|
||
"customerAddress": "Customer address",
|
||
"siteName": "Site",
|
||
"siteAddress": "Site address",
|
||
"contactName": "Contact person",
|
||
"phone": "Phone",
|
||
"email": "E-mail",
|
||
"orderDate": "Order date",
|
||
"documentDate": "Document date",
|
||
"plannedStart": "Planned start",
|
||
"plannedEnd": "Planned end",
|
||
"title": "Title",
|
||
"description": "Description",
|
||
"positions": "Line items",
|
||
"notes": "Notes",
|
||
"totalAmount": "Total amount",
|
||
"references": "References"
|
||
},
|
||
"hints": {
|
||
"date_invalid": "{field}: date not readable.",
|
||
"date_implausible": "{field}: date is unusually far in the past or future.",
|
||
"postal_code_invalid": "{field}: postal code does not have 5 digits.",
|
||
"email_invalid": "{field}: e-mail address format is invalid.",
|
||
"phone_invalid": "{field}: phone number format is invalid.",
|
||
"end_before_start": "{field}: end is before start.",
|
||
"manual_entry": "Automatic recognition is not available. Please enter manually.",
|
||
"ai_budget_exceeded": "The monthly AI allowance is used up – therefore no automatic recognition."
|
||
},
|
||
"positions": {
|
||
"name": "Description",
|
||
"articleNumber": "Article no.",
|
||
"quantity": "Quantity",
|
||
"unit": "Unit",
|
||
"asMaterial": "use as planned material",
|
||
"remove": "Remove line item",
|
||
"add": "Add line item",
|
||
"empty": "No line items recognised."
|
||
}
|
||
},
|
||
"errors": {
|
||
"form_invalid": "Please check the marked fields.",
|
||
"title_required": "Work order title is missing.",
|
||
"customer_required": "Please select a customer.",
|
||
"customer_name_required": "Enter a company name or last name.",
|
||
"site_required": "Please select a site.",
|
||
"site_name_required": "Enter a site name or street.",
|
||
"site_requires_existing_customer": "An existing site requires an existing customer.",
|
||
"email_invalid": "E-mail address format is invalid.",
|
||
"postal_code_invalid": "Postal code must have 5 digits.",
|
||
"end_before_start": "End is before start.",
|
||
"date_invalid": "Date not readable.",
|
||
"quantity_invalid": "Quantity must be a number.",
|
||
"customer_number_taken": "This customer number is already taken. Use the existing customer or clear the number.",
|
||
"import_not_reviewable": "This import has already been handled.",
|
||
"import_not_discardable": "This import can no longer be discarded.",
|
||
"import_not_retryable": "Only failed imports can be processed again.",
|
||
"not_found": "Record not found.",
|
||
"forbidden": "Not allowed.",
|
||
"file_unavailable": "The original file is not available.",
|
||
"dispatch_failed": "Processing could not be started.",
|
||
"error": "Action not possible."
|
||
}
|
||
}
|