Μετάβαση στο περιεχόμενο

Αρχείο αλλαγών

Καταγραφή σημαντικών αλλαγών για την ομάδα ανάπτυξης. Οι νεότερες καταχωρήσεις είναι πάνω.

Μορφή:

Μετά την ημερομηνία [ΕΕΕΕ-ΜΜ-ΗΗ] αφήνουμε κενή γραμμή πριν τα στοιχεία - (αλλιώς το MkDocs τα εμφανίζει ως ένα κομμάτι κειμένου, όχι ως λίστα).

[ΕΕΕΕ-ΜΜ-ΗΗ ΩΩ:ΛΛ] (προαιρετική ζώνη ώρας)
- Σύντομη, συγκεκριμένη αλλαγή (αρχείο ή περιοχή αν βοηθάει)
- …

[2026-04-21]

  • Ραντεβού / πολλαπλά παραστατικά: Το modal ραντεβού υποστηρίζει πλέον σύνδεση με πολλά παραστατικά του ίδιου συναλλασσόμενου. Τα συνδεδεμένα δελτία αποθηκεύονται στο appointments.dochead_ids ως TEXT JSON array αντικειμένων (με id, αριθμό, σειρά, κατάσταση), ενώ το id_dochead παραμένει ως πρώτο/κύριο παραστατικό για συμβατότητα. Στο UI εμφανίζονται πολλαπλοί σύνδεσμοι προς τα δελτία και η επικύρωση ελέγχει ότι όλα τα επιλεγμένα παραστατικά ανήκουν στον ίδιο συναλλασσόμενο (db/migrations/20260421130000_add_dochead_ids_to_appointments.php, AppointmentModel, AppointmentController, add-appointment-modal.html.twig, calendar.js).

  • Αποθήκη / barcode lookup: Στη σελίδα /warehouse/barcodes, όταν αναζητείται είδος με barcode, εμφανίζεται πλέον και ενότητα «Σχετικά παραστατικά» με όλο το ιστορικό παραστατικών του storage, ώστε να φαίνονται και τα κλειστά δελτία μαζί με σειρά, κατάσταση, ημερομηνία παράδοσης και καταχώρησης (ItemStorageModel, barcodes.html.twig, warehouse-barcodes.js).

  • Παραστατικά / εκτύπωση barcode: Στην προβολή δελτίου προστέθηκε ενέργεια «Όλα τα barcode» με επιλογές θερμικής εκτύπωσης 57mm και 80mm, η οποία εκτυπώνει μαζικά όλα τα μοναδικά barcode του δελτίου αντί για ένα-ένα (Documents/edit.html.twig, documents-edit.js).

[2026-04-20]

  • Πελάτης / SCRUM-1724: Σε νέα καταχώρηση (modal «Νέος πελάτης» και ροή «Δημιουργία πελάτη» στο modal ραντεβού) το «Είναι ιδιώτης» είναι προεπιλεγμένο (ΑΦΜ 000000000). Οι υπάρχουσες καρτέλες δεν τροποποιούνται. (add-customer-modal.html.twig, add-appointment-modal.html.twig, skeleton.js, calendar.js, οδηγοί 03-pelatologio.md, 05-rantevou.md).

[2026-04-17]

  • Ραντεβού / προεπιλεγμένος πελάτης: Το CalendarAppointments.openCreateModal(ημερομηνία, { idtrader, lockTrader, hideCreateTrader }) επιτρέπει κλείδωμα του πεδίου συναλλασσόμενου (Select2 disabled) και απόκρυψη του «Δημιουργία πελάτη». Με idtrader μόνο, ενεργοποιούνται από προεπιλογή το lockTrader και το hideCreateTrader. Στην επεξεργασία συναλλασσόμενου, καρτέλα «Ραντεβού», προστέθηκε κουμπί «Νέο ραντεβού» με αυτή τη συμπεριφορά (calendar.js, traders.js, add-appointment-modal.html.twig, Traders/edit.html.twig, docs/odigos-hristi/05-rantevou.md). Το ίδιο κλείδωμα εφαρμόζεται στο modal πριν το κλείσιμο δελτίου παράδοσης (openBeforeCloseDeliveryAppointment).

[2026-04-16]

  • Είδη / επεξεργασία — εμφάνιση τύπου χρέωσης για τεμ.: Στο /items/edit/{id}, όταν η μονάδα μέτρησης είναι τεμ., στη στήλη «Τύπος χρέωσης» και στο dropdown σύνδεσης υπηρεσίας εμφανίζεται πάντα «Σταθερή» για όλες τις υπηρεσίες (ανεξάρτητα από το rate_type στην βάση μέχρι να αποθηκευτεί το είδος)· με αλλαγή μονάδας ανανεώνεται η εμφάνιση (items.js).

  • Είδη / μονάδα τεμ. και τύπος χρέωσης υπηρεσιών: Στο PUT /api/items/{id}, όταν το είδος έχει μονάδα τεμ. (idmunit = 1), όλες οι υπηρεσίες που είναι συνδεδεμένες με το είδος (item_services) ενημερώνονται σε rate_type = flat στον πίνακα services (όσες ήταν by_size). Στο UI η ετικέτα τύπου χρέωσης «Σταθερή» δεν περιλαμβάνει πλέον το (τεμ.) (ItemController, items.js, items.html.twig, traders.js, item.controller.md).

  • Αποθήκη / barcodes — αποθήκευση μόνο κατηγορίας (UI): Στο /warehouse/barcodes το είδος εμφανίζεται σταθερό· η αλλαγή κατηγορίας και η επαναχαρτογράφηση γραμμών γίνονται με κουμπί «Αποθήκευση» κάτω από την κατηγορία. Το API POST /api/warehouse/storage/{id}/change-item-context παραμένει πλήρες (iditem, iditemcategory)· το UI στέλνει το τρέχον είδος (warehouse-barcodes.js, barcodes.html.twig, οδηγός 08-syskeuasia-barcodes.md).

  • Αποθήκη / αλλαγή είδους & επαναχαρτογράφηση υπηρεσιών (backend): Το POST /api/warehouse/storage/{id}/change-item-context (με dry_run και confirm_drop_unmapped) ενημερώνει το item_storage.iditem και τις γραμμές docitems του ίδιου δελτίου (per_item): αντιστοίχιση ανά idservice, τιμές από κατάλογο, συγχώνευση διπλών, διαγραφή μη αντιστοιχίσιμων μετά επιβεβαίωση (WarehouseController, ItemServiceModel::findActiveLinkId, DocumentModel::updateDocitemItemServiceId, warehouse.controller.md).

  • Πελάτης / αναζήτηση (δελτίο & ραντεβού): Στη δημιουργία παραστατικού (documents.js) και στο modal ραντεβού (calendar.js, add-appointment-modal.html.twig) το κείμενο επιλογής πελάτη περιλαμβάνει κινητό, σταθερό και στοιχεία διεύθυνσης, ώστε το Select2 να εντοπίζει τον πελάτη και με αυτά. Ενημερώθηκαν οι οδηγοί docs/odigos-hristi/07-parastatika-kai-delitia.md, 05-rantevou.md.

  • Ραντεβού / φόρτωση λιστών από API: Όταν οι επιλογές συναλλασσόμενου/δρομολογίου/οχήματος φορτώνονται με fetch (χωρίς προ-γεμισμένο HTML), το calendar.js διαβάζει πλέον σωστά το data.traders / data.route_schedules / data.vehicles από την τυπική απάντηση apiSuccess — αποφεύγεται κλήση .map πάνω στο αντικείμενο data.

  • Αποθήκη / barcodes & κατηγορία είδους: Στη σελίδα /warehouse/barcodes, όταν το είδος έχει ενεργές κατηγορίες, εμφανίζεται επιλογή κατηγορίας (όπως στο δελτίο): ο πίνακας υπηρεσιών φιλτράρεται ανά κατηγορία (και εμφανίζονται υπηρεσίες χωρίς υποκατηγορία), η προσθήκη καλεί GET /api/item-services με iditemcategory. Το lookup επιστρέφει item_categories και iditemcategory ανά γραμμή docitems (ItemStorageModel, warehouse-barcodes.js, barcodes.html.twig, οδηγός 08-syskeuasia-barcodes.md).

  • Δελτίο / κατηγορία είδους: Στη δημιουργία παραστατικού, αν το είδος έχει ενεργές κατηγορίες (item_categories), εμφανίζεται επιλογή κατηγορίας είδους· μετά την επιλογή φορτώνονται μόνο οι σχετικές υπηρεσίες (και οι συνδέσεις χωρίς υποκατηγορία, π.χ. Φύλαξη). GET /api/items περιλαμβάνει item_categories ανά είδος· GET /api/item-services?iditem=… δέχεται προαιρετικά iditemcategory (ItemCategoryModel, ItemServiceModel, ItemController, ItemServiceController, public/assets/js/documents.js, ItemApiTest, ItemServiceLinkApiTest).

  • Fylaksi (catalog & documents): Storage is linked per item (per_item): separate item_services / id_item_service per catalog item, not per document. Updated ExpressServiceProvisioner, DocumentModel, DocumentController, CompanyDefaultsService, ItemController, public/assets/js/documents.js; added migration db/migrations/20260416193000_fylaksi_per_item.php; docs express-service-provisioner, company-defaults.service, document.controller.

  • Fylaksi / seed & SQL: New companies get Φύλαξη on every item via ExpressServiceProvisioner::ensureFylaksiOnAllItems after catalog seed (CompanyDefaultsService). Manual DB backfill script: db/sql/fylaksi_per_item_backfill.sql. RegistrationDefaultsTest expectations updated; documents.js calls syncAutoFylaksiLines after auto Πλύσιμο on row load.
  • Documents / With Fylaksi checkbox: public/assets/js/documents.js refetches per-row item_services when enabled (refreshItemServicesCache, patchSvcPickerOptions) so Φύλαξη appears on all rows with a selected item, without clearing other service lines.

  • Τεκμηρίωση / παραστατικά: Στο docs/03-reference/document.controller.md προστέθηκε πλήρες παράδειγμα JSON για POST /api/documents (υποχρεωτικά/προαιρετικά πεδία, iddocseries = 239, with_fylakis / is_express, κανόνες barcode_range, grossval / by_size).

  • API / είδη: Το GET /api/items επιστρέφει για κάθε είδος item_services (ίδια δομή με το GET /api/item-services?iditem=…) και item_categories (ενεργές κατηγορίες). Το GET /api/items/{id} και οι απαντήσεις POST / PUT είδους περιλαμβάνουν τα ίδια πεδία (ItemController, ItemCategoryModel, ItemServiceModel::getGroupedByItemIdForCompany, ItemApiTest).

  • API / πρόσβαση με κλειδί εταιρείας: Τα προστατευμένα endpoints κάτω από /api μπορούν πλέον να κληθούν με την κεφαλίδα X-CARPET-TOKEN, η οποία ταιριάζει με το πεδίο api_token του πίνακα companies. Σε κάθε νέα εταιρεία (εγγραφή) δημιουργείται αυτόματα τυχαίο token 64 hex χαρακτήρων· οι υπάρχουσες εταιρείες παίρνουν token με το migration db/migrations/20260416130000_companies_api_token.php. Η ταυτοποίηση με token εγκαθιστά συνεδρία ως κύριο μέλος της εταιρείας (ιδιοκτήτης πρώτα, αλλιώς πρώτο ενεργό μέλος), με τους ρόλους/δικαιώματά του (Auth::tryBootstrapFromCarpetToken, Middleware, CompanyModel, CompanyUserModel).

  • API / κλειδί ανά χρήστη: Η ίδια κεφαλίδα X-CARPET-TOKEN μπορεί να είναι και το api_token του πίνακα useraccounts (έλεγχος μετά το κλειδί εταιρείας). Η συνεδρία γεμίζει με τον συγκεκριμένο χρήστη και την πρώτη ενεργή εταιρεία του (getFirstCompany), όπως στη σύνδεση με κωδικό. Κάθε νέος λογαριασμός παίρνει token στη δημιουργία· υπάρχοντες χρήστες ενημερώνονται με db/migrations/20260416140000_useraccounts_api_token.php (AccountModel, Auth).
  • Ραντεβού / ανάθεση οδηγού: Προστέθηκε προαιρετική ανάθεση οδηγού (assigned_driver_user_id στον πίνακα appointments, migration db/migrations/20260416150000_appointments_assigned_driver.php). Κενή τιμή σημαίνει ραντεβού ανοιχτό σε όλους τους οδηγούς· με τιμή, επιτρέπονται μόνο μέλη εταιρείας με ρόλο driver. Οι συνδεδεμένοι οδηγοί βλέπουν στη λίστα/API μόνο ραντεβού χωρίς ανάθεση ή ανατεθειμένα στον ίδιο (AppointmentModel, AppointmentController, TraderController, CompanyUserModel::listDriversForCompany, modal, calendar.js, dashboard-calendar.js).
  • Ραντεβού / φίλτρο λίστας οδηγού (API): Στο GET /api/appointments και GET /api/traders/{id}/appointments ο περιορισμός «ανοιχτά ή δικά μου» εφαρμόζεται όταν ο χρήστης έχει ρόλο driver και δεν έχει manage_appointments· όσοι διαχειρίζονται ραντεβού (π.χ. γραμματεία, διαχειριστής) βλέπουν πάντα όλα, ακόμη κι αν έχουν και ρόλο οδηγού (Auth::appointmentsDriverScopeUserId, AppointmentController, TraderController).
  • API / έκδοση κλειδιού με κωδικό: Προστέθηκαν POST /api/auth/token (email ή username + password) για απόκτηση του api_token και χρήση ως X-CARPET-TOKEN (ίδιοι κανόνες / 2FA με τη σύνδεση). Αν χρειάζεται 2FA, require_2fa και POST /api/auth/token/verify-2fa με otp (ίδιο cookie). Λογαριασμοί χωρίς token: AccountModel::ensureApiToken, AuthController, ApiRoutes).

[2026-04-15]

  • Αποθήκη / barcodes: Στην αναζήτηση φυσικού είδους (/warehouse/barcodes, API lookup) οι γραμμές υπηρεσιών φορτώνονται πλέον μόνο για το κύριο παραστατικό του storage (παλαιότερη γραμμή docitems), ώστε να μην επαναλαμβάνονται οι ίδιες υπηρεσίες όταν το ίδιο item_storage συνδέεται με πολλά δελτία (ItemStorageModel).
  • Χρήστες / υποχρεωτική εταιρεία: Δεν επιτρέπεται πλέον ενεργή συνεδρία χωρίς company_id: το Auth::login απαιτεί αριθμό εταιρείας, η σύνδεση και το 2FA απορρίπτονται με μήνυμα αν ο λογαριασμός δεν συνδέεται με εταιρεία, τα view routes (και το admin) περνούν από middleware company, και η αρχική σύνδεση (checkAuthPage) καθαρίζει «σπασμένη» συνεδρία χωρίς εταιρεία (Auth, AuthController, Router, ViewRoutes, AdminRoutes).
  • Εγγραφή / εταιρεία: Μετά την εγγραφή δημιουργείται πάντα εταιρεία και σύνδεση ιδιοκτήτη (seed defaults)· αν λείπει το όνομα εταιρείας, χρησιμοποιείται όνομα/επώνυμο, αλλιώς το τοπικό μέρος του email, αλλιώς η ετικέτα «Εταιρεία». Στο dashboard, αν για κάποιο λόγο λείπει comid στη συνεδρία, γίνεται ανακατεύθυνση στην αρχική σύνδεση (AuthController, HomeController).
  • Πελατολόγιο & ραντεβού / σταθερό τηλέφωνο: Το σταθερό δεν είναι πλέον υποχρεωτικό ούτε στην καρτέλα πελάτη/συνεργάτη ούτε στο ραντεβού· κενό πεδίο αποθηκεύεται ως NULL. Όταν συμπληρώνεται, ελέγχονται 10 ψηφία. Στο UI αφαιρέθηκε το required από το πεδίο επεξεργασίας πελάτη, διορθώθηκε η αποστολή phone στο POST /api/traders (ώστε να μην στέλνεται το κείμενο null μέσω φόρμας), και το ραντεβού στέλνει πάντα tmp_phone ως κείμενο, ώστε στο επεξεργασία να μπορεί να καθαριστεί το σταθερό (TraderController, AppointmentController, edit.html.twig, traders.js, skeleton.js, calendar.js, οδηγός χρήστη).
  • Πελατολόγιο / τιμοκατάλογος πελάτη: Στην επεξεργασία πελάτη (/traders/customers/edit/{id}) προστέθηκε καρτέλα Τιμοκατάλογος με όλα τα είδη και τις συνδεδεμένες υπηρεσίες (ανά είδος)· εμφανίζεται η γενική τιμή καταλόγου και επεξεργάσιμη τιμή πελάτη (item_prices μόνο για τον συγκεκριμένο πελάτη). API: GET /api/traders/{id}/price-catalog, PUT /api/item-prices/{id} (ItemPriceModel, TraderController, ItemPriceController, edit.html.twig, traders.js, TraderApiTest).
  • Προϊόντα / επεξεργασία είδους: Στη σελίδα /items/edit/{id} η γενική τιμή κάθε σύνδεσης υπηρεσίας είναι πλέον επεξεργάσιμη στον πίνακα (πεδίο τιμής + επιβεβαίωση ή Enter)· χρησιμοποιείται το υπάρχον PUT /api/item-services/{id} (public/assets/js/items.js, edit.html.twig).
  • Παραστατικά / φάση παράδοσης (ροή): Το φίλτρο και η στήλη παράδοσης στη λίστα δελτίων χρησιμοποιούν πλέον workflow_delivery_phase (preparation / towards_delivery / delivered) από την αλυσίδα συσχέτισης. Το ίδιο πεδίο εμφανίζεται στην προβολή δελτίου, στο side panel και στα φυσικά είδη του συναλλασσόμενου (DocumentModel, DocumentController, ItemStorageModel, documents-list.js, documents-edit.js, document-panel.js, traders.js, views, DocumentApiTest).
  • Παραστατικά / UI φάσης παράδοσης: Στη λίστα δελτίων και στα φυσικά είδη συναλλασσόμενου η φάση εμφανίζεται ως ετικέτα (Ετοιμασία / Προς παράδοση / Παραδόθηκε) με tooltip «Βήμα 1–3», αντί για μόνο αριθμούς (documents-list.js, traders.js, list.html.twig).

  • Παραστατικά / λίστα δελτίων: Στη σελίδα /documents κάθε αλυσίδα συσχετισμένων δελτίων εμφανίζεται ως μία γραμμή με βάση το δελτίο παραλαβής (σειρά 239)· τα υπόλοιπα (π.χ. προς παράδοση, χρεωστικό) εμφανίζονται στη στήλη Συσχέτιση με συνδέσμους, ταξινομημένα κατά σειρά ροής. Η αναζήτηση και οι εξαγωγές Excel/PDF λαμβάνουν υπόψη και τους αριθμούς/σειρές των συσχετιζόμενων δελτίων (public/assets/js/documents-list.js).

  • Παραστατικά / τιμή υπηρεσίας ανά τ.μ.: Προστέθηκε στήλη docitems.unit_gross (ακαθάριστη τιμή μονάδας €/τ.μ. τη στιγμή του δελτίου). Αν στο νέο δελτίο η ποσότητα τ.μ. είναι 0, το σύνολο γραμμής παραμένει 0 αλλά αποθηκεύεται η μοναδιαία τιμή που βάλατε· όταν καταχωρείτε τ.μ. στην αποθήκη, το σύνολο υπολογίζεται από αυτή (και όχι μόνο από τον κατάλογο). Στη φόρμα νέου δελτίου οι προτεινόμενες τιμές από τον κατάλογο εμφανίζονται πλέον με ΦΠΑ (καθαρή × 1,24), συνεπώς με το backend (DocumentModel, DocumentController, WarehouseController, ItemStorageModel, public/assets/js/documents.js, migration db/migrations/20260415120000_add_unit_gross_to_docitems.php).
  • Tests / DocumentApiTest: Οι κλήσεις δημιουργίας δελτίου και GET /api/documents/next-number χρησιμοποιούν πλέον iddocseries = 239 (δελτίο παραλαβής), ώστε να συμφωνούν με την επικύρωση DocSeries::DELIVERY_SLIP.

  • Παραστατικά / ροή 3 βημάτων (παραλαβή → προς παράδοση → χρεωστικό): Το κλείσιμο εφαρμόζεται πλέον μόνο στο δελτίο παραλαβής (σειρά 239) και δημιουργεί παραστατικό προς παράδοση (σειρά 3) σε κατάσταση ανοιχτό, ώστε να εμφανίζεται το κουμπί «Κλείσιμο → χρεωστικό» (κλείνει το δελτίο παράδοσης και δημιουργεί 3ο παραστατικό με iddocseries = 1 / χρεωστικό). Νέα API διαδρομή POST /api/documents/{id}/charge, ενημερωμένα μηνύματα/επιβεβαιώσεις σε πλήρη σελίδα και side panel (DocSeries, DocumentModel::closeDocument, DocumentController, ApiRoutes, documents-edit.js, document-panel.js, Documents/edit.html.twig, Documents/document_panel.html.twig).

  • Παραστατικά / UX «Προς διακίνηση»: Το πρώτο βήμα εμφανίζεται ως Προς διακίνηση (και στα modals επιβεβαίωσης). Μετά επιτυχές «Προς διακίνηση» ή «Κλείσιμο → χρεωστικό» γίνεται μετάβαση στο νέο παραστατικό (new_id από API) ώστε να μην μένετε σε κλειστό δελτίο χωρίς ενέργειες· στο side panel ανοίγει το νέο id (documents-edit.js, document-panel.js).
  • UI / Modals νέου πελάτη & ραντεβού: Με το κλείσιμο του modal (hidden.bs.modal) καθαρίζονται πλέον όλα τα πεδία, ώστε στο επόμενο άνοιγμα να μην μένουν δεδομένα από προηγούμενη συμπλήρωση ή ακύρωση (public/assets/js/skeleton.js, public/assets/js/calendar.js).
  • UI / Προϊόντα-Υπηρεσίες: Διορθώθηκε η ευθυγράμμιση του form-check form-switch στα modals «Νέο Είδος» και «Νέα Υπηρεσία» στη σελίδα /items, ώστε ο διακόπτης να μην εμφανίζεται εκτός αριστερής πλευράς (public/assets/css/items.css).
  • Ρόλοι χρηστών / μενού & πρόσβαση (views): Εφαρμόστηκε διαχωρισμός ορατότητας στο sidebar για τον ρόλο Γραμματέας (εμφανίζονται: Πελατολόγιο, Προϊόντα/Υπηρεσίες, Ραντεβού, Δρομολόγια, Παραστατικά· αποκρύπτονται: Αναφορές, Εικόνα επιχείρησης, Στοιχεία επιχείρησης, Διαχείριση χρηστών) στο app/Views/Components/sidebar.html.twig.
  • Ρόλοι χρηστών / οδηγός: Ο ρόλος Οδηγός περιορίστηκε ώστε να βλέπει μόνο Πελατολόγιο, Ραντεβού και Παραστατικά. Αποκρύπτονται όλες οι υπόλοιπες ενότητες μενού (συμπεριλαμβανομένης της Αρχικής) και προστέθηκαν route guards για 403 σε dashboard/warehouse όταν δεν επιτρέπεται (app/Views/Components/sidebar.html.twig, app/Routes/ViewRoutes.php).
  • Ρόλοι χρηστών / αποθηκάριος: Ο ρόλος Αποθηκάριος περιορίστηκε ώστε να βλέπει μόνο τη σελίδα barcode (ενότητα «Συσκευασία»). Παράλληλα, τα view route guards για Πελατολόγιο/Ραντεβού/Παραστατικά έγιναν role-based (admin|secretary|driver) ώστε ο αποθηκάριος να λαμβάνει 403 σε κάθε άλλη σελίδα (app/Views/Components/sidebar.html.twig, app/Routes/ViewRoutes.php).
  • Landing redirect ανά ρόλο από /dashboard: Υλοποιήθηκε ενιαίο σημείο εισόδου στο HomeController@index: ο Οδηγός ανακατευθύνεται σε /appointments, ο Αποθηκάριος σε /warehouse/barcodes, ενώ η Γραμματεία παραμένει στο dashboard. Το route /dashboard είναι πλέον προσβάσιμο από όλους τους authenticated ρόλους για μελλοντική role-based αρχική (app/Controllers/View/HomeController.php, app/Routes/ViewRoutes.php, app/Views/Components/sidebar.html.twig).
  • 403 σε μη επιτρεπόμενες σελίδες: Προστέθηκαν route-level έλεγχοι στα view routes ώστε όταν ο χρήστης δεν έχει το απαιτούμενο role/permission να μπλοκάρεται με 403 (χωρίς αλλαγές σε API authorization) στο app/Routes/ViewRoutes.php.
  • Backend modular middleware: Επεκτάθηκε το middleware resolver με role_any: και permission_any: για επαναχρησιμοποιήσιμους κανόνες πρόσβασης σε ομάδες routes (app/Core/Middleware.php).
  • Τεκμηρίωση χρήστη: Ενημερώθηκε ο οδηγός με ενότητα «Μενού ανά ρόλο χρήστη» και σημείωση για 403 σε απευθείας πρόσβαση URL (docs/odigos-hristi/02-i-othoni-kai-to-menou.md).

[2026-04-14]

  • Email / SMTP & TLS: Προστέθηκε Helpers::applyPhpMailerSmtpTlsOptions και μεταβλητή περιβάλλοντος MAIL_SMTP_VERIFY_PEER (προεπιλογή ενεργή επαλήθευση). Με τιμή 0/false απενεργοποιείται ο έλεγχος peer όταν ο πάροχος δίνει πιστοποιητικό με CN διαφορετικό από το MAIL_HOST (χρήση μόνο αν δεν διορθώνεται το hostname). Εφαρμόζεται σε πρόσκληση χρήστη, reset κωδικού (Helpers, AuthController). Ενημερώθηκαν .env.example και docs/01-getting-started/local-setup.md.
  • Πρόσκληση χρήστη / SMTP: Όταν αποτυγχάνει το email πρόσκλησης, το API επιστρέφει πλέον το σφάλμα μεταφοράς (mail_error + κείμενο στο message) για διάγνωση (Helpers::sendUserInvitationEmail, CompanyUserController, settings-users.js).
  • Σύνδεση / ρόλοι & δικαιώματα στη συνεδρία: Στο AuthController::loginUser αφαιρέθηκε το λανθασμένο array_column πάνω στις τιμές που επιστρέφουν ήδη RoleModel::getUserRoles και PermissionModel::getUserPermissions (λίστες string). Προηγουμένως άδειαζαν $_SESSION['roles'] και $_SESSION['permissions'], οπότε δεν λειτουργούσαν έλεγχοι/μενού ανά δικαίωμα (π.χ. «Διαχείριση χρηστών» / manage_users).
  • Πελάτες / κινητό μοναδικό & εύρεση τηλεφώνου: Κινητό μοναδικό και API lookup-contact. Στο modal νέου πελάτη και στην επεξεργασία: μήνυμα κάτω από τα τηλέφωνα, απενεργοποιημένο κουμπί αποθήκευσης όταν ο αριθμός υπάρχει ήδη (χωρίς αυτόματη μετάβαση). Ραντεβού: προεπιλογή συναλλασσόμενου, κείμενο βοήθειας, απόκρυψη «Δημιουργία πελάτη» όταν βρίσκεται υπάρχων (add-customer-modal.html.twig, add-appointment-modal.html.twig, edit.html.twig, skeleton.js, traders.js, calendar.js).

[2026-04-09]

  • Ρυθμίσεις / διαχείριση χρηστών: Νέα σελίδα /settings/users (μενού «Διαχείριση χρηστών» για λογαριασμούς με δικαίωμα manage_users). Προσθήκη μελών με ρόλο Διαχειριστής, Γραμματέας, Αποθηκάριος ή Οδηγός· αποστολή email με προσωρινό κωδικό και σύνδεσμο. API: GET / POST /api/company/users (CompanyUserModel::listMembersWithRoles, CompanyUserController, Helpers::sendUserInvitationEmail, settings-users.js, sidebar.html.twig).
  • Παραστατικά / τιμολόγηση (dochead.invoice): Στη δημιουργία δελτίου παραλαβής επιλέγετε αν το παραστατικό τιμολογείται (προεπιλογή ναι)· αποθηκεύεται invoice 0/1. Η λίστα δελτίων έχει στήλη εικονιδίου· στην προβολή δελτίου, στο πλευρικό panel και στον πίνακα φυσικών ειδών πελάτη εμφανίζεται αν τιμολογείται (create.html.twig, edit.html.twig, list.html.twig, documents.js, documents-list.js, documents-edit.js, document-panel.js, traders.js, DocumentController, DocumentModel::getAll, ItemStorageModel::findStoragesForTrader).
  • Κατάλογος / «Πλύσιμο»: Σε κάθε νέα εταιρεία εξασφαλίζεται η υπηρεσία Πλύσιμο (και μετά το seed τιμών καταλόγου). Κάθε νέο είδος και κάθε νέα υποκατηγορία είδους συνδέονται αυτόματα με Πλύσιμο και γενική τιμή καταλόγου (PlisisimoProvisioner, ItemController, ItemCategoryController, CompanyDefaultsService). Στη δημιουργία δελτίου, μόλις επιλέγετε είδος σε γραμμή, προστίθεται αυτόματα η υπηρεσία Πλύσιμο (αν υπάρχει στον κατάλογο — προτιμάται σύνδεση χωρίς υποκατηγορία) (public/assets/js/documents.js).
  • Αποθήκη / barcodes: Στο αποτέλεσμα αναζήτησης (/warehouse/barcodes) το ονοματεπώνυμο συναλλασσόμενου είναι πλέον σύνδεσμος που ανοίγει την καρτέλα πελάτη ή συνεργάτη σε νέο παράθυρο (target="_blank")· το lookup επιστρέφει trader_type (ItemStorageModel::findFullContextByStorageId, warehouse-barcodes.js).
  • Αποθήκη / ράφι & ποσότητα: Η αποθήκευση «ραφιού & ποσότητας» (PATCH /api/warehouse/storage/{id} με shelf+quantity) απαιτεί πλέον μη κενό ράφι και ποσότητα > 0 (≥ 0,01 για τ.μ.)· ίδιοι έλεγχοι στο UI barcodes και στο modal φυσικού είδους πελατολογίου (WarehouseController::patchStorageShelfAndQuantity, warehouse-barcodes.js, traders.js).
  • Δελτίο / δημιουργία: Η προεπιλογή ποσότητας τ.μ. (είδη ανά τετραγωνικό) στη φόρμα νέου παραστατικού είναι 0 και όχι 1· το API αποδέχεται αποθήκευση 0 στο item_storage (χωρίς εξαναγκασμό σε 1) — ενδεικτικά για υπολογισμούς και κλείσιμο ισχύουν οι υπάρχοντες έλεγχοι τ.μ. (documents.js, DocumentController, DocumentModel).
  • Πελάτης / modal φυσικό είδος (barcode): Όταν λείπει barcode στο είδος αλλά το δελτίο έχει εύρος με διαθέσιμους αριθμούς, το GET /api/warehouse/lookup?storage_id= επιστρέφει pick_choices[] με slot_barcode (ίδια αντιστοίχιση με την αποθήκη)· στο modal εμφανίζεται dropdown για επιλογή γραμμής και «Αποθήκευση barcode» συνδέει τον αριθμό στην επιλεγμένη γραμμή (ItemStorageModel::findStoragesMissingBarcodeOnDocForPick, WarehouseController::lookup, Traders/edit.html.twig, traders.js).
  • Αποθήκη / αναζήτηση barcode: Η επίλυση «μόνο στο εύρος δελτίου» (findStorageIdByDocheadBarcodeRange) χρησιμοποιεί πλέον την ίδια αντιστοίχιση με το εικονικό barcode (mapVirtualBarcodesFromDocheadRange) και όχι parts[idx] — ώστε η σάρωση π.χ. 11 να ανοίγει το σωστό είδος, όχι αυτό που αντιστοιχούσε στο 10 λόγω λάθους θέσης (ItemStorageModel).
  • Αποθήκη / εύρος δελτίου (εικονικό barcode): Η αντιστοίχιση «κενό barcode στο είδος → αριθμός από barcode_range» δεν χρησιμοποιεί πλέον απλά parts[idx] ανά σειρά· αφαιρούνται πρώτα οι αριθμοί που είναι ήδη καταχωρημένοι σε άλλη γραμμή, ώστε να μην εμφανίζονται δύο φορές το ίδιο (π.χ. 11 και 11 αντί για 10 και 11). Νέα μέθοδος ItemStorageModel::mapVirtualBarcodesFromDocheadRange· χρησιμοποιείται και στην προβολή γραμμών δελτίου (DocumentModel::getItemsDetailed).
  • Αποθήκη / εύρος barcode (διόρθωση): Αποφεύγεται αναφορά foreach ($rows as &$row) και κοινό pick_choices array ανά γραμμή — ώστε να μην «αλλοιώνονται» τυχαία τα πεδία barcode/γραμμών σε άλλες εγγραφές JSON. Ίδια λογική στο ItemStorageModel για το virtual barcode (WarehouseController, ItemStorageModel).
  • Αποθήκη / εύρος barcode: Ο πίνακας αποτελεσμάτων Από–Έως παραμένει όπως πριν (στήλες barcode, είδος, ράφι, ποσότητα, παραστατικό, κατάσταση, συναλλασσόμενος)· όταν το barcode προέρχεται από το εύρος δελτίου χωρίς να είναι ακόμα στο είδος, στη στήλη Είδος εμφανίζεται dropdown (pick_choices) με τις γραμμές του δελτίου χωρίς barcode + Σύνδεση. Το GET /by-barcode-range εμπλουτίζει τις εγγραφές με pick_choices όταν needs_barcode_link (WarehouseController::byBarcodeRange, warehouse-barcodes.js, barcodes.html.twig).
  • Αποθήκη / barcodes: Όταν σκανάρετε barcode που ανήκει στο εύρος δελτίου αλλά δεν έχει ακόμα συνδεθεί σε item_storage, εμφανίζεται λίστα επιλογής με τα φυσικά είδη του ίδιου δελτίου που δεν έχουν barcode είδους (είδος + υπηρεσίες)· μετά τη σύνδεση ανοίγει το γνωστό panel. Αν το barcode είναι ήδη στο είδος, η συμπεριφορά παραμένει η ίδια (WarehouseController::lookup, ItemStorageModel, barcodes.html.twig, warehouse-barcodes.js).
  • Αποθήκη / API PATCH /storage/{id}: Ράφι και ποσότητα υποχρεωτικά μαζί στο ίδιο αίτημα· το barcode μόνο σε ξεχωριστό αίτημα (αυστηρό κενό μεταξύ των δύο). Στο modal πελάτη: κουμπί «Αποθήκευση barcode» χωριστά από «Αποθήκευση ραφιού & ποσότητας» (WarehouseController, Traders/edit.html.twig, traders.js).
  • Πελάτης / φυσικά είδη: Στον πίνακα «Υπηρεσίες» (καρτέλα πελάτη) εμφανίζεται το ίδιο barcode μόνο αν έχει καταχωρηθεί στο είδος· αλλιώς εμφανίζεται το εύρος δελτίου (barcode_range) — όχι πλέον «ψευδές» barcode από τη θέση στο εύρος. Στο modal επεξεργασίας φυσικού είδους: πεδίο Barcode είδους (επεξεργάσιμο όταν το δελτίο είναι ανοιχτό), Εύρος δελτίου μόνο ανάγνωση· το PATCH /api/warehouse/storage/{id} δέχεται προαιρετικό barcode (ItemStorageModel::findStoragesForTrader, updateBarcodeForStorage, WarehouseController, traders.js, Traders/edit.html.twig).
  • Δελτίο / barcode (φόρμα δημιουργίας): Δίπλα στο «Πρώτο barcode» εμφανίζεται read-only το πλήρες εύρος που θα αποθηκευτεί στο δελτίο· αφαιρέθηκε το κείμενο βοήθειας κάτω από το πεδίο (create.html.twig, documents.js).
  • Δελτίο / barcode: Στη δημιουργία δελτίου δηλώνεται μόνο το πρώτο barcode· για κάθε είδος εκχωρούνται διαδοχικοί αριθμοί και το πλήρες εύρος αποθηκεύεται μόνο στο dochead (barcode_range) — τα item_storage δημιουργούνται χωρίς barcode (η σάρωση/αποθήκη συνεχίζουν να λειτουργούν μέσω του εύρους του δελτίου). Ενημερώθηκαν DocumentModel::createDocument, getItemsDetailed, ItemStorageModel (εύρος αποθήκης & πελάτης), create.html.twig, documents.js, warehouse-barcodes.js.
  • Υπηρεσίες / «Ανά Παραστατικό»: Η αλλαγή τιμής καταλόγου για υπηρεσία εμβέλειας «ανά παραστατικό» γίνεται πλέον με ενημέρωση της υπάρχουσας σύνδεσης (PUT /api/item-services/{id}) αντί για διαγραφή+δημιουργία — ώστε να μην εμφανίζεται σφάλμα «συσχετισμένες εγγραφές» όταν το δελτίο έχει ήδη γραμμές που δείχνουν σε αυτή τη σύνδεση (ItemServiceController, ItemServiceModel, items.js, ApiRoutes.php).
  • Ραντεβού / εξαγωγή: Excel/PDF από το ημερολόγιο (/appointments, dashboard): καθετη χρονολογική λίστα· φίλτρο ανά προβολή (ημέρα / εβδομάδα / 42ήμερο πλέγμα μήνα μέσω __calendarExportGetRange)· χωρίς στήλη Κατάσταση (appointments-export.js, dashboard-calendar.js, calendar.html.twig, Helpers.php).
  • Παραστατικά / λίστα: Στη λίστα /documents προστέθηκε σύνολο ποσού (€) στο tfoot για τα τρέχοντα φίλτρα, καθώς και εξαγωγή Excel και PDF (ίδια δεδομένα με το φιλτραρισμένο σύνολο)· φόρτωση xlsx / html2pdf από Helpers.php (list.html.twig, documents-list.js).
  • Παραστατικά / λίστα: Στη σελίδα /documents προστέθηκαν φίλτρα Φύλαξη (όλα / με φύλαξη / χωρίς φύλαξη) και Express (όλα / Express / όχι Express), μαζί με τον καθαρισμό φίλτρων (list.html.twig, documents-list.js).
  • Παραστατικά / λίστα: Στη στήλη Συσχέτιση (/documents) εμφανίζεται πλέον η περιγραφή σειράς του συσχετισμένου δελτίου (π.χ. ΔΕΛΤΙΟ ΠΑΡΑΛΑΒΗΣ / ΠΑΡΑΔΟΣΗΣ) μαζί με τον αριθμό δελτίου, όχι μόνο #…· το GET /api/documents επιστρέφει correlated_series_descr, correlated_series_code (DocumentModel::getAll, documents-list.js).
  • Παραστατικά / καρτέλα πελάτη: Όταν ανοίγει η φόρμα ραντεβού πριν το κλείσιμο δελτίου από το πλευρικό panel (π.χ. /traders/customers/edit/…), το offcanvas κλείνει πρόσκαιρα ώστε το modal ραντεβού να εμφανίζεται μπροστά· σε ακύρωση το panel ξανανοίγει. Κλήση init() στην openBeforeCloseDeliveryAppointment ώστε να είναι σίγουρα δεμένα handlers φόρμας (calendar.js).
  • Παραστατικά / ραντεβού πριν κλείσιμο: Όταν ανοίγει η φόρμα ραντεβού από το βήμα «πρώτα ραντεβού παράδοσης», το τρέχον δελτίο παραλαβής παραμένει προεπιλεγμένο στη σύνδεση παραστατικού (δεν ακυρώνεται πλέον από την αλλαγή πελάτη στο modal ούτε από επανάληψη ανανέωσης της λίστας)· calendar.js (__docCloseAfterApptSave, onTraderOrCreateModeChanged, openBeforeCloseDeliveryAppointment).
  • Παραστατικά / UI: Οι επιβεβαιώσεις κλεισίματος δελτίου και του προαιρετικού βήματος «ραντεβού πριν το κλείσιμο» χρησιμοποιούν πλέον Toast.confirm (@tsirosgeorge/toastnotification, κεντρική επιβεβαίωση με overlay) αντί για window.confirm (documents-edit.js, document-panel.js).
  • Παραστατικά / κλείσιμο & ραντεβού: Αν δεν υπάρχει ήδη ραντεβού με id_dochead = το δελτίο παραλαβής που κλείνετε, μπορεί να ερωτηθείτε αν θέλετε πρώτα ραντεβού παράδοσης· αποθηκεύετε το ραντεβού με σύνδεση στο τρέχον δελτίο παραλαβής, και μετά εκτελείται το κλείσιμο (POST …/close) ώστε το repointDeliveryAppointmentsToNewDeliveryDoc να μεταφέρει τη σύνδεση στο νέο δελτίο αποστολής (CalendarAppointments.openBeforeCloseDeliveryAppointment, handleFormSubmit στο calendar.js, documents-edit.js, document-panel.js). Το GET /api/documents/{id} επιστρέφει linked_appointment_count· το POST …/close επιστρέφει new_iddocseries, new_series_descr.
  • Πελάτης / UI: Στην καρτέλα πελάτη, στήλη «Παραστατικό» (φυσικά είδη) και στήλη «Δελτίο» (ραντεβού) εμφανίζεται πλέον η περιγραφή σειράς (docseries.descr, π.χ. ΔΕΛΤΙΟ ΠΑΡΑΛΑΒΗΣ) αντί του κωδικού σειράς (CODE)· fallback στον κωδικό αν λείπει περιγραφή (ItemStorageModel::findStoragesForTrader πεδίο series_descr, traders.js — τα ραντεβού είχαν ήδη doc_series_descr στο API).
  • Παραστατικά / λίστα: Στη λίστα δελτίων (/documents) το όνομα συναλλασσόμενου είναι σύνδεσμος προς την καρτέλα επεξεργασίας (/traders/customers/edit/… ή …/partners/… ανάλογα με τον τύπο)· το API λίστας επιστρέφει πλέον trader_type (DocumentModel::getAll, documents-list.js).
  • Παραστατικά / slider (offcanvas): Στο πλευρικό panel προβολής παραστατικού (π.χ. από σελίδα πελάτη) προστέθηκε κουμπί Κλείσιμο παραστατικού για ανοιχτά δελτία — ίδια επιβεβαίωση και κλήση POST /api/documents/{id}/close με την πλήρη σελίδα (document_panel.html.twig, document-panel.js).
  • Παραστατικά / ροή: Μετά την επιτυχή δημιουργία δελτίου από τη φόρμα (/documents/create), η εφαρμογή μεταφέρει πλέον στη λίστα παραστατικών (/documents) αντί να ανοίγει ξανά τη φόρμα νέου δελτίου (public/assets/js/documents.js).
  • UI / εικονίδια: Προστέθηκαν εικονίδια Font Awesome σε κουμπιά και ενέργειες (ημερολόγιο: προβολή Μήνα/Εβδομάδα/Ημέρα, Νέος Πελάτης, Νέο Ραντεβού· modals νέου πελάτη/ραντεβού· dropdown «Νέο» στο navbar· Άκυρο σε φόρμες επεξεργασίας συναλλασσόμενου/δρομολογίου/οχήματος/προγράμματος· σελίδες σφαλμάτων 403/404/405). Αρχεία: calendar.html.twig, add-appointment-modal.html.twig, add-customer-modal.html.twig, navbar.html.twig, Traders/edit.html.twig, Routes/edit.html.twig, Vehicles/edit.html.twig, Schedules/edit.html.twig, Errors/403|404|405.html.twig.
  • Παραστατικά / UI: Αφαιρέθηκε η εμφάνιση τύπου χρέωσης υπηρεσίας (σταθερό / ανά τ.μ.) από την προβολή δελτίου (documents-edit.js) και από τη φόρμα νέου δελτίου (documents.js) — παραμένει η λογική τιμολόγησης στο data-rate / calculateTotals.
  • UI / ειδοποιήσεις: Το toast-helper.js καλούσε bare toast· σε ορισμένα περιβάλλοντα το toast δεν είναι στο global scope και προκαλούσε ReferenceError: toast is not defined (π.χ. μετά από ενέργεια στην αποθήκη barcodes). Χρησιμοποιείται πλέον ρητά window.toast· ενημερώθηκαν documents-edit.js, traders.js, skeleton.js (__appToast).
  • Παραστατικά / αποθήκη: Όταν το δελτίο είναι κλειστό (doc_status = closed), αποκλείονται επεξεργασία μέσω API αποθήκης (ράφι, τ.μ., γραμμές υπηρεσιών, προσθήκη υπηρεσίας) και διαγραφή δελτίου· DocumentModel::mutationBlockReason, WarehouseController, DocumentController::destroy· ειδοποίηση και απενεργοποίηση πεδίων στο warehouse-barcodes.js, modal αποθήκης στο traders.js, μπάνερ προβολής στο documents-edit.js / edit.html.twig, barcodes.html.twig.
  • Ραντεβού / δελτία: Όταν κλείνει δελτίο παραλαβής (σειρά 239) και δημιουργείται το δελτίο παράδοσης, τα ραντεβού τύπου παράδοση που ήταν συνδεδεμένα με το κλειστό δελτίο ενημερώνονται αυτόματα ώστε το id_dochead να δείχνει στο νέο παραστατικό παράδοσης (DocumentModel::closeDocument, AppointmentModel::repointDeliveryAppointmentsToNewDeliveryDoc).
  • Ραντεβού / δελτία: Στο modal ραντεβού, όταν ο τύπος είναι παράδοση αλλά το συνδεδεμένο ανοιχτό δελτίο είναι ακόμα παραλαβής (σειρά 239), ο σύνδεσμος δεν εμφανίζει πλέον «Παραστατικό παράδοσης» — εμφανίζεται «Δεν έχει κοπεί ακόμα παραστατικό παράδοσης»· όταν το δελτίο είναι η σειρά παράδοσης (ζεύξη, codeid 3), παραμένει «Παραστατικό παράδοσης». Προστέθηκε iddocseries στα ανοιχτά παραστατικά (DocumentModel::findOpenDocumentsForTrader) και doc_iddocseries στα ραντεβού (AppointmentModel), ενημερώθηκε public/assets/js/calendar.js.
  • Ραντεβού / δελτία: Στο calendar.js προστέθηκε σταθερά DOCUMENT_VIEW_BASE (/documents) για τον σύνδεσμο «συνδεδεμένο παραστατικό» στο modal ραντεβού (ξεκάθαρο ότι δεν χρησιμοποιείται /docs/ της τεκμηρίωσης).
  • Δρομολόγηση / δελτία: Οι σελίδες δελτίων (views) μεταφέρθηκαν από /docs/... σε /documents/... ώστε να μην συγκρούεται με το στατικό MkDocs στο /docs/· ενημερώθηκαν app/Routes/ViewRoutes.php, μενού (sidebar, navbar), Twig δελτίων/συναλλασσομένων, και JS (documents.js, documents-list.js, documents-edit.js, document-panel.js, calendar.js, warehouse-barcodes.jsdocs/01-getting-started/architecture-overview.md.
  • Τεκμηρίωση / MkDocs: Στο mkdocs.yml ορίστηκε use_directory_urls: false ώστε να παράγεται public/docs/changelog.html (και γενικά .html ανά σελίδα) αντί για μόνο changelog/index.html· ενημερώθηκαν docs/README.md και docs/01-getting-started/local-setup.md.
  • Cursor / ρυθμίσεις: Ενημερώθηκε το .cursorrules ώστε το mkdocs build να ζητείται και όταν αλλάζει το changelog.md στη ρίζα ή το mkdocs.yml (όχι μόνο τα Markdown κάτω από docs/).
  • Τεκμηρίωση / MkDocs: Το docs/changelog.md ενσωματώνει πλέον το changelog.md της ρίζας μέσω pymdownx.snippets (αντί για symlink)· προστέθηκε ρητή αναφορά στην αρχική σελίδα τεκμηρίωσης (docs/README.md)· ενημερώθηκαν mkdocs.yml και docs/01-getting-started/local-setup.md.
  • Τεκμηρίωση / MkDocs: Το public/docs/ δεν αγνοείται στο .gitignore (για commit)· διαγράφηκε ο παλιός φάκελος site/ και προστέθηκε site/ στο .gitignore (προεπιλογή MkDocs ./site/)· ενημερώθηκε το docs/01-getting-started/local-setup.md.
  • Τεκμηρίωση / MkDocs: Προστέθηκαν mkdocs.yml, requirements-docs.txt, και οδηγίες στο docs/01-getting-started/local-setup.md· το mkdocs build παράγει HTML στο public/docs/ (URL /docs/). Σελίδα ιστορικού: docs/changelog.md (περιεχόμενο από changelog.md στη ρίζα)· ενημερώθηκε το docs/README.md.

[2026-04-06]

  • Τεκμηρίωση χρήστη: Προστέθηκε docs/odigos-hristi/ — αναλυτικός οδηγός για τελικούς χρήστες (μενού, ροές εργασίας, συμπεριφορά πελατολογίου, δελτίων, ραντεβού, αποθήκης, χωρίς προγραμματιστική ορολογία). Αναδιοργάνωση docs/README.md· τα παλιά 02-features/*.md αντικαταστάθηκαν από ανακατεύθυνση στον οδηγό χρήσης.
  • Τεκμηρίωση: Προστέθηκε φάκελος docs/ με οδηγό εγκατάστασης, επισκόπηση αρχιτεκτονικής, και σκελετοί αναφοράς ανά module (03-reference/)· όλα στα ελληνικά.
  • Συναλλασσόμενοι / modal νέου πελάτη: Διόρθωση ώστε το κενό πεδίο κωδικού να μην στέλνεται ως συμβολοσειρά "null" μέσω URLSearchParams· έτσι εφαρμόζεται η αυτόματη ανάθεση κωδικών PEL-#### όταν το πεδίο αφήνεται κενό (public/assets/js/skeleton.js).
  • Συναλλασσόμενοι / modal νέου πελάτη: Η επιλογή «Είναι ιδιώτης» εμφανίζεται πάντα (όχι μόνο από το ημερολόγιο)· η συμπεριφορά ΑΦΜ 000000000 παραμένει ίδια (add-customer-modal.html.twig, skeleton.js).
  • Παραστατικά / δημιουργία: Προεπιλογή χωρίς τικ σε «Με Φύλαξη» και «Express»· στο JS χρήση ρητού checked === true· ευθυγράμμιση προεπιλογών API για with_fylakis / is_express (create.html.twig, documents.js, DocumentController.php).
  • Παραστατικά / δημιουργία: Προκαταβολή επιτρέπεται να υπερβαίνει το σύνολο του παραστατικού· αφαιρέθηκαν όρια στον client και στον server· παραμένει μόνο ο έλεγχος μη αρνητικής τιμής (documents.js, DocumentController.php).