From 92ec321d089fa7c4db3e12d79529dce6ecc464af Mon Sep 17 00:00:00 2001
From: Ollama
Date: Wed, 1 Apr 2026 06:57:54 +0000
Subject: [PATCH 01/13] fix: Clear sale session after completing sale
The clear_all() calls in postComplete() were placed after return
statements, making them unreachable dead code. This caused the
completed sale to remain in the session and appear in the Register
when navigating back.
The fix moves clear_all() and clear_mode() calls before the return
statements so they are actually executed, properly clearing the sale
cart, customer, and payments from the session after sale completion.
This fixes the regression reported by @odiea where users had to
manually cancel sales after each transaction.
---
app/Controllers/Sales.php | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/Controllers/Sales.php b/app/Controllers/Sales.php
index 628ae5057..da4a428c6 100644
--- a/app/Controllers/Sales.php
+++ b/app/Controllers/Sales.php
@@ -786,8 +786,8 @@ class Sales extends Secure_Controller
$data['error_message'] = lang('Sales.transaction_failed');
} else {
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']);
- return view('sales/' . $invoice_view, $data);
$this->sale_lib->clear_all();
+ return view('sales/' . $invoice_view, $data);
}
}
} elseif ($this->sale_lib->is_work_order_mode()) {
@@ -820,9 +820,9 @@ class Sales extends Secure_Controller
$data['barcode'] = null;
- return view('sales/work_order', $data);
$this->sale_lib->clear_mode();
$this->sale_lib->clear_all();
+ return view('sales/work_order', $data);
}
} elseif ($this->sale_lib->is_quote_mode()) {
$data['sales_quote'] = lang('Sales.quote');
@@ -848,9 +848,9 @@ class Sales extends Secure_Controller
$data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']);
$data['barcode'] = null;
- return view('sales/quote', $data);
$this->sale_lib->clear_mode();
$this->sale_lib->clear_all();
+ return view('sales/quote', $data);
}
} else {
// Save the data to the sales table
@@ -871,8 +871,8 @@ class Sales extends Secure_Controller
$data['error_message'] = lang('Sales.transaction_failed');
} else {
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']);
- return view('sales/receipt', $data);
$this->sale_lib->clear_all();
+ return view('sales/receipt', $data);
}
}
}
From a5bbb2bcc56df59691f814926fd26d1a2a5d6ed5 Mon Sep 17 00:00:00 2001
From: Ollama
Date: Wed, 1 Apr 2026 07:16:15 +0000
Subject: [PATCH 02/13] fix: Remove redundant clear_mode() calls
clear_all() already calls clear_mode() internally, so the separate
clear_mode() calls were redundant.
---
app/Controllers/Sales.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/app/Controllers/Sales.php b/app/Controllers/Sales.php
index da4a428c6..c618a82e0 100644
--- a/app/Controllers/Sales.php
+++ b/app/Controllers/Sales.php
@@ -820,7 +820,6 @@ class Sales extends Secure_Controller
$data['barcode'] = null;
- $this->sale_lib->clear_mode();
$this->sale_lib->clear_all();
return view('sales/work_order', $data);
}
@@ -848,7 +847,6 @@ class Sales extends Secure_Controller
$data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']);
$data['barcode'] = null;
- $this->sale_lib->clear_mode();
$this->sale_lib->clear_all();
return view('sales/quote', $data);
}
From f761e1464f6ab9fac67172c2f7ee5f68b4691173 Mon Sep 17 00:00:00 2001
From: Ollama
Date: Wed, 1 Apr 2026 05:58:53 +0000
Subject: [PATCH 03/13] Translate missing strings in multiple languages
- Add Calendar.php translation file for es-ES, nl-NL, de-DE
- Fill empty string translations in Common.php for de-DE, nl-NL, fr, it, pt-BR
- Translate UBL invoice strings (ubl_invoice, download_ubl, ubl_generation_failed) in Sales.php
- Add toggle_cost_and_profit in Reports.php for all languages
- Translate error_deleting_admin and error_updating_admin in Employees.php
- Translate csv_import_invalid_location error message in Items.php
- Update various missing translations for administrator, clerk, manager, dashboard, etc.
Languages updated: Spanish (es-ES), Dutch (nl-NL), German (de-DE), French (fr), Italian (it), Portuguese (pt-BR)
---
app/Language/de-DE/Calendar.php | 49 ++++++++++++++++++++++++++++++++
app/Language/de-DE/Common.php | 32 ++++++++++-----------
app/Language/de-DE/Employees.php | 14 ++++-----
app/Language/de-DE/Items.php | 2 +-
app/Language/de-DE/Reports.php | 1 +
app/Language/de-DE/Sales.php | 4 +++
app/Language/es-ES/Calendar.php | 49 ++++++++++++++++++++++++++++++++
app/Language/es-ES/Employees.php | 4 +--
app/Language/es-ES/Items.php | 2 +-
app/Language/es-ES/Reports.php | 1 +
app/Language/es-ES/Sales.php | 4 +++
app/Language/fr/Common.php | 20 ++++++-------
app/Language/fr/Employees.php | 14 ++++-----
app/Language/fr/Items.php | 2 +-
app/Language/fr/Reports.php | 1 +
app/Language/fr/Sales.php | 4 +++
app/Language/it/Common.php | 26 ++++++++---------
app/Language/it/Employees.php | 14 ++++-----
app/Language/it/Items.php | 2 +-
app/Language/it/Reports.php | 1 +
app/Language/it/Sales.php | 4 +++
app/Language/nl-NL/Calendar.php | 49 ++++++++++++++++++++++++++++++++
app/Language/nl-NL/Common.php | 32 ++++++++++-----------
app/Language/nl-NL/Employees.php | 14 ++++-----
app/Language/nl-NL/Items.php | 2 +-
app/Language/nl-NL/Reports.php | 1 +
app/Language/nl-NL/Sales.php | 4 +++
app/Language/pt-BR/Common.php | 22 +++++++-------
app/Language/pt-BR/Employees.php | 14 ++++-----
app/Language/pt-BR/Items.php | 2 +-
app/Language/pt-BR/Reports.php | 1 +
app/Language/pt-BR/Sales.php | 4 +++
32 files changed, 286 insertions(+), 109 deletions(-)
create mode 100644 app/Language/de-DE/Calendar.php
create mode 100644 app/Language/es-ES/Calendar.php
create mode 100644 app/Language/nl-NL/Calendar.php
diff --git a/app/Language/de-DE/Calendar.php b/app/Language/de-DE/Calendar.php
new file mode 100644
index 000000000..7c95a27e6
--- /dev/null
+++ b/app/Language/de-DE/Calendar.php
@@ -0,0 +1,49 @@
+ "So",
+ "mo" => "Mo",
+ "tu" => "Di",
+ "we" => "Mi",
+ "th" => "Do",
+ "fr" => "Fr",
+ "sa" => "Sa",
+ "sun" => "Son",
+ "mon" => "Mon",
+ "tue" => "Die",
+ "wed" => "Mit",
+ "thu" => "Don",
+ "fri" => "Fre",
+ "sat" => "Sam",
+ "sunday" => "Sonntag",
+ "monday" => "Montag",
+ "tuesday" => "Dienstag",
+ "wednesday" => "Mittwoch",
+ "thursday" => "Donnerstag",
+ "friday" => "Freitag",
+ "saturday" => "Samstag",
+ "jan" => "Jan",
+ "feb" => "Feb",
+ "mar" => "Mär",
+ "apr" => "Apr",
+ "may" => "Mai",
+ "jun" => "Jun",
+ "jul" => "Jul",
+ "aug" => "Aug",
+ "sep" => "Sep",
+ "oct" => "Okt",
+ "nov" => "Nov",
+ "dec" => "Dez",
+ "january" => "Januar",
+ "february" => "Februar",
+ "march" => "März",
+ "april" => "April",
+ "mayl" => "Mai",
+ "june" => "Juni",
+ "july" => "Juli",
+ "august" => "August",
+ "september" => "September",
+ "october" => "Oktober",
+ "november" => "November",
+ "december" => "Dezember",
+];
\ No newline at end of file
diff --git a/app/Language/de-DE/Common.php b/app/Language/de-DE/Common.php
index f5204dde7..8f70d5ef6 100644
--- a/app/Language/de-DE/Common.php
+++ b/app/Language/de-DE/Common.php
@@ -3,18 +3,18 @@
return [
"address_1" => "Adresse 1",
"address_2" => "Adresse 2",
- "admin" => "",
+ "admin" => "Administrator",
"city" => "Stadt",
- "clerk" => "",
+ "clerk" => "Angestellter",
"close" => "Schließen",
- "color" => "",
+ "color" => "Theme-Farben",
"comments" => "Kommentare",
"common" => "Allgemein",
"confirm_search" => "Sie haben eine oder mehrere Zeilen gewählt. Nach der Verarbeitung werden diese nicht mehr ausgewählt sein. Wollen Sie die Suche dennoch verarbeiten?",
"copyrights" => "© 2010 - {0}",
"correct_errors" => "Bitte korrigieren Sie vor dem Speichern die angezeigten Fehler",
"country" => "Land",
- "dashboard" => "",
+ "dashboard" => "Dashboard",
"date" => "Datum",
"delete" => "Löschen",
"det" => "Details",
@@ -26,15 +26,15 @@ return [
"export_csv_no" => "Nein",
"export_csv_yes" => "Ja",
"fields_required_message" => "Die Felder in rot sind erforderlich",
- "fields_required_message_unique" => "",
+ "fields_required_message_unique" => "Die rot markierten Felder sind erforderlich und müssen eindeutig sein",
"first_name" => "Vorname",
"first_name_required" => "Vorname ist erforderlich.",
"first_page" => "Erste",
"gender" => "Geschlecht",
"gender_female" => "W",
"gender_male" => "M",
- "gender_undefined" => "",
- "icon" => "",
+ "gender_undefined" => "Undefiniert",
+ "icon" => "Symbol",
"id" => "ID",
"import" => "Import",
"import_change_file" => "Ändern",
@@ -48,21 +48,21 @@ return [
"last_page" => "Letzte",
"learn_about_project" => "für neueste Nachrichten zum Projekt.",
"list_of" => "Liste von",
- "logo" => "",
- "logo_mark" => "",
+ "logo" => "Logo",
+ "logo_mark" => "Marke",
"logout" => "Ausloggen",
- "manager" => "",
+ "manager" => "Manager",
"migration_needed" => "Eine Datenbankmigration auf {0} wird nach der Anmeldung gestartet.",
"new" => "Neu",
- "no" => "",
+ "no" => "Nein",
"no_persons_to_display" => "Keine Personen zum Anzeigen.",
"none_selected_text" => "[auswählen]",
"or" => "Oder",
- "people" => "",
+ "people" => "Personen",
"phone_number" => "Telefon",
"phone_number_required" => "Telefon ist erforderlich",
"please_visit_my" => "Bitte beuschen Sie",
- "position" => "",
+ "position" => "Position",
"powered_by" => "Unterstützt von",
"price" => "Preis",
"print" => "Drucken",
@@ -73,8 +73,8 @@ return [
"search" => "Suche",
"search_options" => "Suchkriterien",
"searched_for" => "Gescuht nach",
- "software_short" => "",
- "software_title" => "",
+ "software_short" => "OSPOS",
+ "software_title" => "Open Source Point of Sale",
"state" => "BL/Kanton",
"submit" => "Senden",
"total_spent" => "Gesamtausgaben",
@@ -83,7 +83,7 @@ return [
"website" => "Website",
"welcome" => "Willkommen",
"welcome_message" => "Willkommen bei OSPOS, zum Beginnen auf ein Modul klicken.",
- "yes" => "",
+ "yes" => "Ja",
"you_are_using_ospos" => "Sie verwenden Open Source Point Of Sale Version",
"zip" => "PLZ",
];
diff --git a/app/Language/de-DE/Employees.php b/app/Language/de-DE/Employees.php
index bfc49ff9c..3e4230714 100644
--- a/app/Language/de-DE/Employees.php
+++ b/app/Language/de-DE/Employees.php
@@ -1,26 +1,26 @@
"",
+ "administrator" => "Administrator",
"basic_information" => "Mitarbeiter-Information",
"cannot_be_deleted" => "Konnte gewählten Mitarbeiter nicht löschen, einer oder mehrere weisen Verkäufe aus.",
- "change_employee" => "",
+ "change_employee" => "Mitarbeiter ändern",
"change_password" => "Passwort Ändern",
- "clerk" => "",
- "commission" => "",
+ "clerk" => "Angestellter",
+ "commission" => "Provision",
"confirm_delete" => "Wollen Sie diesen Mitarbeiter wirklich löschen?",
"confirm_restore" => "Möchten Sie die ausgewählten Mitarbeiter wiederherstellen?",
"current_password" => "Aktuelles Passwort",
"current_password_invalid" => "Aktuelles Passwort ist ungültig.",
"employee" => "Mitarbeiter",
"error_adding_updating" => "Fehler beim Hinzufügen/Ändern.",
- "error_deleting_admin" => "",
- "error_updating_admin" => "",
+ "error_deleting_admin" => "Sie können keinen Administrator löschen.",
+ "error_updating_admin" => "Sie können keinen Administrator ändern.",
"error_deleting_demo_admin" => "Sie können den Demo-Administrator nicht löschen.",
"error_updating_demo_admin" => "Sie können den Demo-Administrator nicht verändern.",
"language" => "Sprache",
"login_info" => "Mitarbeiter Login",
- "manager" => "",
+ "manager" => "Manager",
"new" => "Neuer Mitarbeiter",
"none_selected" => "Sie haben keine Mitarbeiter zum Löschen gewählt.",
"one_or_multiple" => "Mitarbeiter",
diff --git a/app/Language/de-DE/Items.php b/app/Language/de-DE/Items.php
index 371067ed3..fff52d06f 100644
--- a/app/Language/de-DE/Items.php
+++ b/app/Language/de-DE/Items.php
@@ -26,7 +26,7 @@ return [
"cost_price_required" => "Der Großhandelspreis ist ein Pflichtfeld.",
"count" => "Ändere Bestand",
"csv_import_failed" => "CSV Import fehlgeschlagen",
- "csv_import_invalid_location" => "",
+ "csv_import_invalid_location" => "Ungültige Lagerorte gefunden: {0}. Nur gültige Lagerorte sind erlaubt.",
"csv_import_nodata_wrongformat" => "Die hochgeladene Datei enthält keine Daten oder ist falsch formatiert.",
"csv_import_partially_failed" => "{0} Artikel-Import Fehler in Zeile: {1}. Keine Reihen wurden importiert.",
"csv_import_success" => "Artikelimport erfolgreich.",
diff --git a/app/Language/de-DE/Reports.php b/app/Language/de-DE/Reports.php
index 01b97977b..c6b08075b 100644
--- a/app/Language/de-DE/Reports.php
+++ b/app/Language/de-DE/Reports.php
@@ -146,4 +146,5 @@ return [
"used" => "Punkte eingelöst",
"work_orders" => "Arbeitsaufträge",
"zero_and_less" => "Null und weniger",
+ "toggle_cost_and_profit" => "Kosten & Gewinn umschalten",
];
diff --git a/app/Language/de-DE/Sales.php b/app/Language/de-DE/Sales.php
index 18ad986ad..198ff239f 100644
--- a/app/Language/de-DE/Sales.php
+++ b/app/Language/de-DE/Sales.php
@@ -222,4 +222,8 @@ return [
"work_order_number_duplicate" => "Arbeitsauftragsnummer muss eindeutig sein.",
"work_order_sent" => "Arbeitsauftrag gesendet an",
"work_order_unsent" => "Der Arbeitsauftrag konnte nicht gesendet werden an",
+ "sale_not_found" => "Verkauf nicht gefunden",
+ "ubl_invoice" => "UBL-Rechnung",
+ "download_ubl" => "UBL-Rechnung herunterladen",
+ "ubl_generation_failed" => "UBL-Rechnung konnte nicht erstellt werden",
];
diff --git a/app/Language/es-ES/Calendar.php b/app/Language/es-ES/Calendar.php
new file mode 100644
index 000000000..e58476325
--- /dev/null
+++ b/app/Language/es-ES/Calendar.php
@@ -0,0 +1,49 @@
+ "Do",
+ "mo" => "Lu",
+ "tu" => "Ma",
+ "we" => "Mi",
+ "th" => "Ju",
+ "fr" => "Vi",
+ "sa" => "Sá",
+ "sun" => "Dom",
+ "mon" => "Lun",
+ "tue" => "Mar",
+ "wed" => "Mié",
+ "thu" => "Jue",
+ "fri" => "Vie",
+ "sat" => "Sáb",
+ "sunday" => "Domingo",
+ "monday" => "Lunes",
+ "tuesday" => "Martes",
+ "wednesday" => "Miércoles",
+ "thursday" => "Jueves",
+ "friday" => "Viernes",
+ "saturday" => "Sábado",
+ "jan" => "Ene",
+ "feb" => "Feb",
+ "mar" => "Mar",
+ "apr" => "Abr",
+ "may" => "May",
+ "jun" => "Jun",
+ "jul" => "Jul",
+ "aug" => "Ago",
+ "sep" => "Sep",
+ "oct" => "Oct",
+ "nov" => "Nov",
+ "dec" => "Dic",
+ "january" => "Enero",
+ "february" => "Febrero",
+ "march" => "Marzo",
+ "april" => "Abril",
+ "mayl" => "Mayo",
+ "june" => "Junio",
+ "july" => "Julio",
+ "august" => "Agosto",
+ "september" => "Septiembre",
+ "october" => "Octubre",
+ "november" => "Noviembre",
+ "december" => "Diciembre",
+];
\ No newline at end of file
diff --git a/app/Language/es-ES/Employees.php b/app/Language/es-ES/Employees.php
index 613d5cb44..513721ba4 100644
--- a/app/Language/es-ES/Employees.php
+++ b/app/Language/es-ES/Employees.php
@@ -14,8 +14,8 @@ return [
"current_password_invalid" => "Contraseña Actual Inválida.",
"employee" => "Empleado",
"error_adding_updating" => "Error al agregar/actualizar empleado.",
- "error_deleting_admin" => "",
- "error_updating_admin" => "",
+ "error_deleting_admin" => "No puedes eliminar un usuario administrador.",
+ "error_updating_admin" => "No puedes modificar un usuario administrador.",
"error_deleting_demo_admin" => "No puedes borrar el usuario admin del demo.",
"error_updating_demo_admin" => "No puedes cambiar el usuario admin del demo.",
"language" => "Idioma",
diff --git a/app/Language/es-ES/Items.php b/app/Language/es-ES/Items.php
index aa7ab8eef..47d087105 100644
--- a/app/Language/es-ES/Items.php
+++ b/app/Language/es-ES/Items.php
@@ -26,7 +26,7 @@ return [
"cost_price_required" => "Precio al Por Mayor es un campo requerido.",
"count" => "Actualizar Inventario",
"csv_import_failed" => "Falló la importación de Hoja de Cálculo",
- "csv_import_invalid_location" => "",
+ "csv_import_invalid_location" => "Ubicación(es) de stock inválida(s) encontrada(s): {0}. Solo ubicaciones de stock válidas son permitidas.",
"csv_import_nodata_wrongformat" => "El archivo subido no tiene datos o el formato es incorrecto.",
"csv_import_partially_failed" => "Hubo {0} falla(s) en la importación de producto(s) en la(s) línea(s): {1}. Ninguna fila ha sido importada.",
"csv_import_success" => "Se importaron los articulos exitosamente.",
diff --git a/app/Language/es-ES/Reports.php b/app/Language/es-ES/Reports.php
index 04c1de2f9..f7f86371e 100644
--- a/app/Language/es-ES/Reports.php
+++ b/app/Language/es-ES/Reports.php
@@ -146,4 +146,5 @@ return [
"used" => "Puntos usados",
"work_orders" => "Ordenes",
"zero_and_less" => "Cero y negativos",
+ "toggle_cost_and_profit" => "Alternar Costo y Ganancia",
];
diff --git a/app/Language/es-ES/Sales.php b/app/Language/es-ES/Sales.php
index 3c29182f0..a337f7539 100644
--- a/app/Language/es-ES/Sales.php
+++ b/app/Language/es-ES/Sales.php
@@ -222,5 +222,9 @@ return [
"work_order_number_duplicate" => "El numero de orden de trabajo debe ser unico.",
"work_order_sent" => "Orden de trabajo enviada a",
"work_order_unsent" => "Orden de trabajo fallida al enviar a",
+ "sale_not_found" => "Venta no encontrada",
+ "ubl_invoice" => "Factura UBL",
+ "download_ubl" => "Descargar Factura UBL",
+ "ubl_generation_failed" => "Error al generar la factura UBL",
"selected_customer" => "Cliente seleccionado",
];
diff --git a/app/Language/fr/Common.php b/app/Language/fr/Common.php
index 056c15ec8..d8dc85f84 100644
--- a/app/Language/fr/Common.php
+++ b/app/Language/fr/Common.php
@@ -3,18 +3,18 @@
return [
"address_1" => "Adresse 1",
"address_2" => "Adresse 2",
- "admin" => "",
+ "admin" => "Administrateur",
"city" => "Ville",
- "clerk" => "",
+ "clerk" => "Employé",
"close" => "Fermer",
- "color" => "",
+ "color" => "Couleurs du thème",
"comments" => "Commentaires",
"common" => "commun",
"confirm_search" => "Vous avez sélectionné une ou plusieurs lignes, celles-ci ne seront plus sélectionnées après votre recherche. Voulez-vous continuer ?",
"copyrights" => "© 2010 - {0}",
"correct_errors" => "Merci de corriger les erreurs identifiées avant d'enregistrer",
"country" => "Pays",
- "dashboard" => "",
+ "dashboard" => "Tableau de bord",
"date" => "Date",
"delete" => "Supprimer",
"det" => "détails",
@@ -26,14 +26,14 @@ return [
"export_csv_no" => "Non",
"export_csv_yes" => "Oui",
"fields_required_message" => "Les champs en rouge sont requis",
- "fields_required_message_unique" => "",
+ "fields_required_message_unique" => "Les champs en rouge sont requis et doivent être uniques",
"first_name" => "Prénom",
"first_name_required" => "Le prénom est requis.",
"first_page" => "Premier",
"gender" => "Genre",
"gender_female" => "F",
"gender_male" => "M",
- "gender_undefined" => "",
+ "gender_undefined" => "Non défini",
"icon" => "Icône",
"id" => "Identifiant",
"import" => "Importation",
@@ -51,18 +51,18 @@ return [
"logo" => "Logo",
"logo_mark" => "Marque",
"logout" => "Déconnexion",
- "manager" => "",
+ "manager" => "Gestionnaire",
"migration_needed" => "Une migration de la base de donnée vers {0} démarrera après le connexion.",
"new" => "Nouveau",
- "no" => "Oui",
+ "no" => "Non",
"no_persons_to_display" => "Il n'y a personne à afficher.",
"none_selected_text" => "[Sélectionner]",
"or" => "OU",
- "people" => "",
+ "people" => "Personnes",
"phone_number" => "Téléphone",
"phone_number_required" => "Le numéro de téléphone est requis.",
"please_visit_my" => "SVP visitez le",
- "position" => "",
+ "position" => "Position",
"powered_by" => "Propulsé par",
"price" => "Prix",
"print" => "Imprimer",
diff --git a/app/Language/fr/Employees.php b/app/Language/fr/Employees.php
index 789649ae7..b347698bb 100644
--- a/app/Language/fr/Employees.php
+++ b/app/Language/fr/Employees.php
@@ -1,26 +1,26 @@
"",
+ "administrator" => "Administrateur",
"basic_information" => "Fiche",
"cannot_be_deleted" => "Impossible de supprimer le(s) employé(s) sélectionné(s),car un ou plusieur a éffectué une vente, ou car vous essayez de vous supprimer vous-meme.",
- "change_employee" => "",
+ "change_employee" => "Changer d'employé",
"change_password" => "Changement de mot de passe",
- "clerk" => "",
- "commission" => "",
+ "clerk" => "Employé",
+ "commission" => "Commission",
"confirm_delete" => "Êtes-vous certain de vouloir supprimer le(s) employé(s) sélectionné(s) ?",
"confirm_restore" => "Êtes-vous certain de vouloir restaurer le(s) employé(s) selectionné(s) ?",
"current_password" => "Mot de passe actuel",
"current_password_invalid" => "Le mot de passe actuel est invalide.",
"employee" => "Employé",
"error_adding_updating" => "Erreur d'ajout/édition d'employé.",
- "error_deleting_admin" => "",
- "error_updating_admin" => "",
+ "error_deleting_admin" => "Vous ne pouvez pas supprimer un utilisateur administrateur.",
+ "error_updating_admin" => "Vous ne pouvez pas modifier un utilisateur administrateur.",
"error_deleting_demo_admin" => "Vous ne pouvez pas supprimer l'utilisateur de démonstration admin.",
"error_updating_demo_admin" => "Vous ne pouvez pas modifier l'utilisateur de démonstration admin.",
"language" => "Langue",
"login_info" => "Connexion",
- "manager" => "",
+ "manager" => "Gestionnaire",
"new" => "Nouvel employé",
"none_selected" => "Aucun employé sélectionné pour la suppression.",
"one_or_multiple" => "employé(s)",
diff --git a/app/Language/fr/Items.php b/app/Language/fr/Items.php
index 85c90f15e..0dfbd44d5 100644
--- a/app/Language/fr/Items.php
+++ b/app/Language/fr/Items.php
@@ -26,7 +26,7 @@ return [
"cost_price_required" => "Le prix de gros est requis.",
"count" => "Mise à jour de l'inventaire",
"csv_import_failed" => "Échec d'import CSV",
- "csv_import_invalid_location" => "",
+ "csv_import_invalid_location" => "Emplacement(s) de stock invalide(s) trouvé(s) : {0}. Seuls les emplacements de stock valides sont autorisés.",
"csv_import_nodata_wrongformat" => "Le CSV envoyé ne contient aucune donnée, ou elles sont dans un format erroné.",
"csv_import_partially_failed" => "Il y a eu {0} importation(s) d'articles échoué(s) au(x) ligne(s) : {1}. Aucune ligne n'a été importée.",
"csv_import_success" => "Importation des articles réussie.",
diff --git a/app/Language/fr/Reports.php b/app/Language/fr/Reports.php
index 1758e42e0..2050611a6 100644
--- a/app/Language/fr/Reports.php
+++ b/app/Language/fr/Reports.php
@@ -146,4 +146,5 @@ return [
"used" => "Points utilisés",
"work_orders" => "Ordre Du Travail",
"zero_and_less" => "Zéro ou moin",
+ "toggle_cost_and_profit" => "Basculer Coût & Profit",
];
diff --git a/app/Language/fr/Sales.php b/app/Language/fr/Sales.php
index c81e58ce8..34caae2f4 100644
--- a/app/Language/fr/Sales.php
+++ b/app/Language/fr/Sales.php
@@ -222,4 +222,8 @@ return [
"work_order_number_duplicate" => "Le numéro de bon de travail doit être unique.",
"work_order_sent" => "Ordre de travail envoyé à",
"work_order_unsent" => "L'ordre de travail n'a pas pu être envoyé à",
+ "sale_not_found" => "Vente introuvable",
+ "ubl_invoice" => "Facture UBL",
+ "download_ubl" => "Télécharger Facture UBL",
+ "ubl_generation_failed" => "Échec de la génération de la facture UBL",
];
diff --git a/app/Language/it/Common.php b/app/Language/it/Common.php
index ded83079c..03737f7b4 100644
--- a/app/Language/it/Common.php
+++ b/app/Language/it/Common.php
@@ -3,18 +3,18 @@
return [
"address_1" => "Indirizzo 1",
"address_2" => "Indirizzo 2",
- "admin" => "",
+ "admin" => "Amministratore",
"city" => "Città",
- "clerk" => "",
+ "clerk" => "Impiegato",
"close" => "Chiudere",
- "color" => "",
+ "color" => "Colori del tema",
"comments" => "Commenti",
"common" => "comune",
"confirm_search" => "Hai selezionato una o più righe, queste non saranno più selezionate dopo la tua ricerca. Sei sicuro di voler procedere alla ricerca?",
"copyrights" => "© 2010 - {0}",
"correct_errors" => "Correggi gli errori identificati prima di salvare",
"country" => "Paese",
- "dashboard" => "",
+ "dashboard" => "Pannello di controllo",
"date" => "Data",
"delete" => "Cancella",
"det" => "dettagli",
@@ -26,14 +26,14 @@ return [
"export_csv_no" => "No",
"export_csv_yes" => "Si",
"fields_required_message" => "I campi in rosso sono richiesti",
- "fields_required_message_unique" => "",
+ "fields_required_message_unique" => "I campi in rosso sono richiesti e devono essere unici",
"first_name" => "Nome",
"first_name_required" => "Campo Nome è richiesto.",
"first_page" => "Primo",
"gender" => "Sesso",
"gender_female" => "F",
"gender_male" => "M",
- "gender_undefined" => "",
+ "gender_undefined" => "Non definito",
"icon" => "Icona",
"id" => "ID",
"import" => "Importa",
@@ -51,18 +51,18 @@ return [
"logo" => "Logo",
"logo_mark" => "Marchio",
"logout" => "Esci",
- "manager" => "",
- "migration_needed" => "",
+ "manager" => "Manager",
+ "migration_needed" => "Una migrazione del database verso {0} inizierà dopo l'accesso.",
"new" => "Nuovo",
- "no" => "",
+ "no" => "No",
"no_persons_to_display" => "Non ci sono persone da mostrare.",
"none_selected_text" => "[Selezionare]",
"or" => "OR",
- "people" => "",
+ "people" => "Persone",
"phone_number" => "Numero di Telefono",
- "phone_number_required" => "",
+ "phone_number_required" => "Numero di Telefono è richiesto",
"please_visit_my" => "Visitare il",
- "position" => "",
+ "position" => "Posizione",
"powered_by" => "Sviluppato da",
"price" => "Prezzo",
"print" => "Stampa",
@@ -83,7 +83,7 @@ return [
"website" => "Sito web",
"welcome" => "Benvenuto",
"welcome_message" => "Benvenuto in OSPOS, clicca un modulo sottostante per incominciare.",
- "yes" => "",
+ "yes" => "Sì",
"you_are_using_ospos" => "Stai usando la versione Open Source Point Of Sale (Punto di vendita)",
"zip" => "CAP",
];
diff --git a/app/Language/it/Employees.php b/app/Language/it/Employees.php
index cce612d2f..bb2529d8f 100644
--- a/app/Language/it/Employees.php
+++ b/app/Language/it/Employees.php
@@ -1,26 +1,26 @@
"",
+ "administrator" => "Amministratore",
"basic_information" => "Informazioni",
"cannot_be_deleted" => "Eliminazione dell'impiegato/i non consentita, uno o più hanno trattato delle vendite o stai cancellando il tuo account.",
- "change_employee" => "",
+ "change_employee" => "Cambia Impiegato",
"change_password" => "Cambia Password",
- "clerk" => "",
- "commission" => "",
+ "clerk" => "Impiegato",
+ "commission" => "Commissione",
"confirm_delete" => "Sei sicuro di voler eliminare l'impiegato/i selezionato?",
"confirm_restore" => "Sei sicuro di voler ripristinare gl'Impiegati selezionati?",
"current_password" => "Password Corrente",
"current_password_invalid" => "Password corrente non valida.",
"employee" => "Impiegato",
"error_adding_updating" => "Aggiunta o aggiornamento di impiegati fallito.",
- "error_deleting_admin" => "",
- "error_updating_admin" => "",
+ "error_deleting_admin" => "Non puoi eliminare un utente amministratore.",
+ "error_updating_admin" => "Non puoi modificare un utente amministratore.",
"error_deleting_demo_admin" => "Non puoi eliminare l'utente admin demo.",
"error_updating_demo_admin" => "Non puoi cambiare l'utente admin demo.",
"language" => "Lingua",
"login_info" => "Login",
- "manager" => "",
+ "manager" => "Manager",
"new" => "Nuovo Impiegato",
"none_selected" => "Non hai selezionato nessun impiegato da eliminare.",
"one_or_multiple" => "impiegato/i",
diff --git a/app/Language/it/Items.php b/app/Language/it/Items.php
index 2acadfb33..6f4f47e97 100644
--- a/app/Language/it/Items.php
+++ b/app/Language/it/Items.php
@@ -26,7 +26,7 @@ return [
"cost_price_required" => "Prezzo all'ingrosso è un campo obbligatorio.",
"count" => "Aggiorna Inventario",
"csv_import_failed" => "Importazione CSV fallita",
- "csv_import_invalid_location" => "",
+ "csv_import_invalid_location" => "Trovata/e locazione/i di stock non valida/e: {0}. Solo le locazioni di stock valide sono ammesse.",
"csv_import_nodata_wrongformat" => "L'upload del file non ha dati o non è formattato correttamente.",
"csv_import_partially_failed" => "Si sono verificati {0} errori di importazione degli elementi nelle righe: {1}. Nessuna riga è stata importata.",
"csv_import_success" => "Importazione CSV dell'articolo riuscita.",
diff --git a/app/Language/it/Reports.php b/app/Language/it/Reports.php
index b461daa9b..9a0d9cc0d 100644
--- a/app/Language/it/Reports.php
+++ b/app/Language/it/Reports.php
@@ -146,4 +146,5 @@ return [
"used" => "Punti Usati",
"work_orders" => "Ordini di lavoro",
"zero_and_less" => "Zero e meno",
+ "toggle_cost_and_profit" => "Commuta Costo & Profitto",
];
diff --git a/app/Language/it/Sales.php b/app/Language/it/Sales.php
index c62a4c94c..84d9a65a2 100644
--- a/app/Language/it/Sales.php
+++ b/app/Language/it/Sales.php
@@ -222,4 +222,8 @@ return [
"work_order_number_duplicate" => "Numero Ordine di Lavoro deve essere unico.",
"work_order_sent" => "Ordine di lavoro inviato",
"work_order_unsent" => "Ordine di Lavoro fallito da inviare a",
+ "sale_not_found" => "Vendita non trovata",
+ "ubl_invoice" => "Fattura UBL",
+ "download_ubl" => "Scarica fattura UBL",
+ "ubl_generation_failed" => "Impossibile generare la fattura UBL",
];
diff --git a/app/Language/nl-NL/Calendar.php b/app/Language/nl-NL/Calendar.php
new file mode 100644
index 000000000..d0b31c40b
--- /dev/null
+++ b/app/Language/nl-NL/Calendar.php
@@ -0,0 +1,49 @@
+ "Zo",
+ "mo" => "Ma",
+ "tu" => "Di",
+ "we" => "Wo",
+ "th" => "Do",
+ "fr" => "Vr",
+ "sa" => "Za",
+ "sun" => "Zon",
+ "mon" => "Maa",
+ "tue" => "Din",
+ "wed" => "Woe",
+ "thu" => "Don",
+ "fri" => "Vri",
+ "sat" => "Zat",
+ "sunday" => "Zondag",
+ "monday" => "Maandag",
+ "tuesday" => "Dinsdag",
+ "wednesday" => "Woensdag",
+ "thursday" => "Donderdag",
+ "friday" => "Vrijdag",
+ "saturday" => "Zaterdag",
+ "jan" => "Jan",
+ "feb" => "Feb",
+ "mar" => "Maa",
+ "apr" => "Apr",
+ "may" => "Mei",
+ "jun" => "Jun",
+ "jul" => "Jul",
+ "aug" => "Aug",
+ "sep" => "Sep",
+ "oct" => "Okt",
+ "nov" => "Nov",
+ "dec" => "Dec",
+ "january" => "Januari",
+ "february" => "Februari",
+ "march" => "Maart",
+ "april" => "April",
+ "mayl" => "Mei",
+ "june" => "Juni",
+ "july" => "Juli",
+ "august" => "Augustus",
+ "september" => "September",
+ "october" => "Oktober",
+ "november" => "November",
+ "december" => "December",
+];
\ No newline at end of file
diff --git a/app/Language/nl-NL/Common.php b/app/Language/nl-NL/Common.php
index fdf91bbdb..bce8314cc 100644
--- a/app/Language/nl-NL/Common.php
+++ b/app/Language/nl-NL/Common.php
@@ -3,18 +3,18 @@
return [
"address_1" => "Adres 1",
"address_2" => "Adres 2",
- "admin" => "",
+ "admin" => "Beheerder",
"city" => "Plaats",
- "clerk" => "",
+ "clerk" => "Bediende",
"close" => "Sluiten",
- "color" => "",
+ "color" => "Thema-kleuren",
"comments" => "Opmerkingen",
"common" => "algemeen",
"confirm_search" => "U heeft één of meerdere rijen geselecteerd, deze zullen niet langer geselecteerd zijn na uw zoekopdracht. Weet u zeker dat u deze zoekopdracht wilt verzenden?",
"copyrights" => "© 2010 - {0}",
"correct_errors" => "Geïdentificeerd fouten oplossen voor het opslaan",
"country" => "Land",
- "dashboard" => "",
+ "dashboard" => "Dashboard",
"date" => "Datum",
"delete" => "Verwijderen",
"det" => "details",
@@ -26,14 +26,14 @@ return [
"export_csv_no" => "Nee",
"export_csv_yes" => "Ja",
"fields_required_message" => "Rode velden zijn vereist",
- "fields_required_message_unique" => "",
+ "fields_required_message_unique" => "Rode velden zijn vereist en moeten uniek zijn",
"first_name" => "Voornaam",
"first_name_required" => "Voornaam is een vereist veld.",
"first_page" => "Eerste",
"gender" => "Geslacht",
"gender_female" => "V",
"gender_male" => "M",
- "gender_undefined" => "",
+ "gender_undefined" => "Ongedefinieerd",
"icon" => "Pictogram",
"id" => "ID",
"import" => "Importeren",
@@ -49,20 +49,20 @@ return [
"learn_about_project" => "om de laatste informatie over het project te bekijken.",
"list_of" => "Lijst van",
"logo" => "Logo",
- "logo_mark" => "",
+ "logo_mark" => "Merk",
"logout" => "Afmelden",
- "manager" => "",
+ "manager" => "Manager",
"migration_needed" => "Een databasemigratie naar {0} zal starten na aanmelding.",
"new" => "Nieuw",
- "no" => "",
+ "no" => "Nee",
"no_persons_to_display" => "Er zijn geen personen om te weergeven.",
"none_selected_text" => "[Selecteren]",
"or" => "OF",
- "people" => "",
+ "people" => "Personen",
"phone_number" => "Telefoonnummer",
- "phone_number_required" => "",
+ "phone_number_required" => "Telefoonnummer is vereist",
"please_visit_my" => "Bezoek de",
- "position" => "",
+ "position" => "Positie",
"powered_by" => "Mogelijk gemaakt door",
"price" => "Prijs",
"print" => "Afdrukken",
@@ -73,8 +73,8 @@ return [
"search" => "Zoeken",
"search_options" => "Zoek opties",
"searched_for" => "Gezocht naar",
- "software_short" => "",
- "software_title" => "",
+ "software_short" => "OSPOS",
+ "software_title" => "Open Source Point of Sale",
"state" => "Provincie",
"submit" => "Verzenden",
"total_spent" => "Totaal uitgegeven",
@@ -83,7 +83,7 @@ return [
"website" => "opensourcepos.org",
"welcome" => "Welkom",
"welcome_message" => "Welkom bij OSPOS, klik op een module hieronder om te beginnen.",
- "yes" => "",
- "you_are_using_ospos" => "",
+ "yes" => "Ja",
+ "you_are_using_ospos" => "U gebruikt Open Source Point Of Sale Versie",
"zip" => "Postcode",
];
diff --git a/app/Language/nl-NL/Employees.php b/app/Language/nl-NL/Employees.php
index f288602c3..578958608 100644
--- a/app/Language/nl-NL/Employees.php
+++ b/app/Language/nl-NL/Employees.php
@@ -1,26 +1,26 @@
"",
+ "administrator" => "Beheerder",
"basic_information" => "Informatie",
"cannot_be_deleted" => "Kan geselecteerde werknemer(s) niet verwijderen, één of meerdere bevatten verwerkte verkopen of u probeert uw account te verwijderen.",
- "change_employee" => "",
+ "change_employee" => "Werknemer wijzigen",
"change_password" => "Wachtwoord wijzigen",
- "clerk" => "",
- "commission" => "",
+ "clerk" => "Bediende",
+ "commission" => "Commissie",
"confirm_delete" => "Weet u zeker dat u de geselecteerde werknemer(s) wilt verwijderen?",
"confirm_restore" => "Weet u zeker dat u de geselecteerde werknemer(s) wilt herstellen?",
"current_password" => "Huidige wachtwoord",
"current_password_invalid" => "Huidige wachtwoord is ongeldig.",
"employee" => "Werknemer",
"error_adding_updating" => "Werknemer toevoegen of bijwerken mislukt.",
- "error_deleting_admin" => "",
- "error_updating_admin" => "",
+ "error_deleting_admin" => "U kunt een beheerder niet verwijderen.",
+ "error_updating_admin" => "U kunt een beheerder niet wijzigen.",
"error_deleting_demo_admin" => "Kan de demo admin gebruiker niet verwijderen.",
"error_updating_demo_admin" => "Kan de demo admin gebruiker niet wijzigen.",
"language" => "Taal",
"login_info" => "Aanmelden",
- "manager" => "",
+ "manager" => "Manager",
"new" => "Nieuwe werknemer",
"none_selected" => "Geen werknemer(s) geselecteerd om te verwijderen.",
"one_or_multiple" => "werknemer(s)",
diff --git a/app/Language/nl-NL/Items.php b/app/Language/nl-NL/Items.php
index d220b11ed..f19220cc0 100644
--- a/app/Language/nl-NL/Items.php
+++ b/app/Language/nl-NL/Items.php
@@ -26,7 +26,7 @@ return [
"cost_price_required" => "Inkoopprijs is een vereist veld.",
"count" => "Voorraad bijwerken",
"csv_import_failed" => "CSV importeren mislukt",
- "csv_import_invalid_location" => "",
+ "csv_import_invalid_location" => "Ongeldige voorraadlocatie(s) gevonden: {0}. Alleen geldige voorraadlocaties zijn toegestaan.",
"csv_import_nodata_wrongformat" => "Het geüploade CSV-bestand bevat geen gegevens or heeft de verkeerde indeling.",
"csv_import_partially_failed" => "Er zijn {0} artikel import fout(en) in lijn(en): {1}. Geen rijen geïmporteerd.",
"csv_import_success" => "Artikel CSV geïmporteerd.",
diff --git a/app/Language/nl-NL/Reports.php b/app/Language/nl-NL/Reports.php
index d330efec6..7f57c89f5 100644
--- a/app/Language/nl-NL/Reports.php
+++ b/app/Language/nl-NL/Reports.php
@@ -146,4 +146,5 @@ return [
"used" => "Punten gebruikt",
"work_orders" => "Werkorders",
"zero_and_less" => "Nul en minder",
+ "toggle_cost_and_profit" => "Kosten en winst wisselen",
];
diff --git a/app/Language/nl-NL/Sales.php b/app/Language/nl-NL/Sales.php
index e9cdce8a3..e37c31c23 100644
--- a/app/Language/nl-NL/Sales.php
+++ b/app/Language/nl-NL/Sales.php
@@ -222,4 +222,8 @@ return [
"work_order_number_duplicate" => "Werkordernummer moet uniek zijn.",
"work_order_sent" => "Werkorder verzonden naar",
"work_order_unsent" => "Werkorder niet verzonden naar",
+ "sale_not_found" => "Verkoop niet gevonden",
+ "ubl_invoice" => "UBL-factuur",
+ "download_ubl" => "UBL-factuur downloaden",
+ "ubl_generation_failed" => "Genereren van UBL-factuur mislukt",
];
diff --git a/app/Language/pt-BR/Common.php b/app/Language/pt-BR/Common.php
index 7a6d5f84a..474980b82 100644
--- a/app/Language/pt-BR/Common.php
+++ b/app/Language/pt-BR/Common.php
@@ -3,18 +3,18 @@
return [
'address_1' => "Endereço",
'address_2' => "Complemento",
- 'admin' => "",
+ 'admin' => "Administrador",
'city' => "Cidade",
- 'clerk' => "",
+ 'clerk' => "Funcionário",
'close' => "Fechar",
- 'color' => "",
+ 'color' => "Cores do tema",
'comments' => "Comentários",
'common' => "comum",
'confirm_search' => "Você selecionou uma ou mais linhas, estes não serão mais selecionados após a sua pesquisa. Tem certeza de que deseja enviar esta pesquisa?",
'copyrights' => "© 2010 - {0}",
'correct_errors' => "Por favor, corrija os erros identificados antes de salvar",
'country' => "País",
- 'dashboard' => "",
+ 'dashboard' => "Painel",
'date' => "Data",
'delete' => "Apagar",
'det' => "detalhes",
@@ -26,14 +26,14 @@ return [
'export_csv_no' => "Não",
'export_csv_yes' => "Sim",
'fields_required_message' => "Campos em vermelho são obrigatórios",
- 'fields_required_message_unique' => "",
+ 'fields_required_message_unique' => "Campos em vermelho são obrigatórios e devem ser únicos",
'first_name' => "Nome",
'first_name_required' => "O nome é requerido.",
'first_page' => "Primeira",
'gender' => "Sexo",
'gender_female' => "F",
'gender_male' => "M",
- 'gender_undefined' => "",
+ 'gender_undefined' => "Indefinido",
'icon' => "Ícone",
'id' => "Id",
'import' => "Importar",
@@ -51,18 +51,18 @@ return [
'logo' => "Logotipo",
'logo_mark' => "Símbolo da marca",
'logout' => "Sair",
- 'manager' => "",
+ 'manager' => "Gerente",
'migration_needed' => "Uma migração do banco de dados para {0} será iniciada após o login.",
'new' => "Novo",
- 'no' => "nao",
+ 'no' => "Não",
'no_persons_to_display' => "Não existem pessoas para mostrar.",
'none_selected_text' => "Selecione",
'or' => "ou",
- 'people' => "",
+ 'people' => "Pessoas",
'phone_number' => "Telefone",
'phone_number_required' => "Número do telefone é requerido",
'please_visit_my' => "Para saber mais sobre esta aplicação visite o website do projeto |",
- 'position' => "",
+ 'position' => "Posição",
'powered_by' => "Desenvolvido por",
'price' => "Preço",
'print' => "Imprimir",
@@ -83,7 +83,7 @@ return [
'website' => "opensourcepos.org",
'welcome' => "Bem-vindo",
'welcome_message' => "Bem-vindo.",
- 'yes' => "sim",
+ 'yes' => "Sim",
'you_are_using_ospos' => "Você está usando Open Source Point Of Sale Versão",
'zip' => "CEP",
];
diff --git a/app/Language/pt-BR/Employees.php b/app/Language/pt-BR/Employees.php
index 655d2bf6e..d9e38bd98 100644
--- a/app/Language/pt-BR/Employees.php
+++ b/app/Language/pt-BR/Employees.php
@@ -1,26 +1,26 @@
"",
+ "administrator" => "Administrador",
"basic_information" => "Informações do Funcionário",
"cannot_be_deleted" => "Não foi possível excluir funcionários selecionados, um ou mais dos funcionários processou vendas ou você está tentando excluir-se :).",
- "change_employee" => "",
+ "change_employee" => "Alterar Funcionário",
"change_password" => "Alterar senha",
- "clerk" => "",
- "commission" => "",
+ "clerk" => "Funcionário",
+ "commission" => "Comissão",
"confirm_delete" => "Tem certeza de que deseja excluir os funcionários selecionados?",
"confirm_restore" => "Tem certeza de que deseja restaurar o (s) empregado (s) selecionado (s)?",
"current_password" => "Senha atual",
"current_password_invalid" => "Senha atual inválida.",
"employee" => "Funcionário",
"error_adding_updating" => "Erro ao adicionar/atualizar funcionário.",
- "error_deleting_admin" => "",
- "error_updating_admin" => "",
+ "error_deleting_admin" => "Você não pode excluir um usuário administrador.",
+ "error_updating_admin" => "Você não pode modificar um usuário administrador.",
"error_deleting_demo_admin" => "Você não pode excluir o usuário administrador de demonstração.",
"error_updating_demo_admin" => "Você não pode alterar o usuário de demonstração de administração.",
"language" => "Linguagem",
"login_info" => "Autenticação",
- "manager" => "",
+ "manager" => "Gerente",
"new" => "Novo Funcionário",
"none_selected" => "Você não selecionou nenhum funcionário para excluir.",
"one_or_multiple" => "funcionário(s)",
diff --git a/app/Language/pt-BR/Items.php b/app/Language/pt-BR/Items.php
index b35b4c117..0ed149a84 100644
--- a/app/Language/pt-BR/Items.php
+++ b/app/Language/pt-BR/Items.php
@@ -26,7 +26,7 @@ return [
"cost_price_required" => "Preço de custo é um campo obrigatório.",
"count" => "Acrescentar ao Inventário",
"csv_import_failed" => "Importação do CSV falhou",
- "csv_import_invalid_location" => "",
+ "csv_import_invalid_location" => "Local(is) de estoque inválido(s) encontrado(s): {0}. Apenas locais de estoque válidos são permitidos.",
"csv_import_nodata_wrongformat" => "Seu arquivo enviado não contém dados ou formato errado.",
"csv_import_partially_failed" => "Houve {0} falha na importação de itens na(s) linha(s): {1}. Nenhuma linha foi importada.",
"csv_import_success" => "Importação de Itens com sucesso.",
diff --git a/app/Language/pt-BR/Reports.php b/app/Language/pt-BR/Reports.php
index 8c3ad09c2..f51e5a8d4 100644
--- a/app/Language/pt-BR/Reports.php
+++ b/app/Language/pt-BR/Reports.php
@@ -146,4 +146,5 @@ return [
"used" => "Pontos usados",
"work_orders" => "Ordens de trabalho",
"zero_and_less" => "Zero e menor",
+ "toggle_cost_and_profit" => "Alternar Custo & Lucro",
];
diff --git a/app/Language/pt-BR/Sales.php b/app/Language/pt-BR/Sales.php
index 1456d5c28..5f87ba959 100644
--- a/app/Language/pt-BR/Sales.php
+++ b/app/Language/pt-BR/Sales.php
@@ -222,4 +222,8 @@ return [
"work_order_number_duplicate" => "O número da ordem de serviço deve ser exclusivo.",
"work_order_sent" => "Ordem de trabalho enviada para",
"work_order_unsent" => "A ordem de serviço não foi enviada para",
+ "sale_not_found" => "Venda não encontrada",
+ "ubl_invoice" => "Fatura UBL",
+ "download_ubl" => "Baixar Fatura UBL",
+ "ubl_generation_failed" => "Falha ao gerar fatura UBL",
];
From 493d9cc9c1b07f62ccc40ddfcc2b1ae9c680244d Mon Sep 17 00:00:00 2001
From: Ollama
Date: Wed, 1 Apr 2026 06:43:34 +0000
Subject: [PATCH 04/13] Fix translation issues from code review
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Use 'Bénéfice' in French Reports.php for consistency with 'profit' key
- Fix Italian grammar: 'Il numero di telefono è richiesto'
- Use 'Responsabile' for 'manager' in Italian Common.php
- Add 'sale_not_found' translation key to missing languages (km, ml, ta, ur)
- Tamil (ta) gets proper translation, others get English fallback
---
app/Language/fr/Reports.php | 2 +-
app/Language/it/Common.php | 4 ++--
app/Language/km/Sales.php | 1 +
app/Language/ml/Sales.php | 1 +
app/Language/ta/Sales.php | 1 +
app/Language/ur/Sales.php | 1 +
6 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/app/Language/fr/Reports.php b/app/Language/fr/Reports.php
index 2050611a6..3c8f0a0f0 100644
--- a/app/Language/fr/Reports.php
+++ b/app/Language/fr/Reports.php
@@ -146,5 +146,5 @@ return [
"used" => "Points utilisés",
"work_orders" => "Ordre Du Travail",
"zero_and_less" => "Zéro ou moin",
- "toggle_cost_and_profit" => "Basculer Coût & Profit",
+ "toggle_cost_and_profit" => "Basculer Coût & Bénéfice",
];
diff --git a/app/Language/it/Common.php b/app/Language/it/Common.php
index 03737f7b4..5bb34d433 100644
--- a/app/Language/it/Common.php
+++ b/app/Language/it/Common.php
@@ -51,7 +51,7 @@ return [
"logo" => "Logo",
"logo_mark" => "Marchio",
"logout" => "Esci",
- "manager" => "Manager",
+ "manager" => "Responsabile",
"migration_needed" => "Una migrazione del database verso {0} inizierà dopo l'accesso.",
"new" => "Nuovo",
"no" => "No",
@@ -60,7 +60,7 @@ return [
"or" => "OR",
"people" => "Persone",
"phone_number" => "Numero di Telefono",
- "phone_number_required" => "Numero di Telefono è richiesto",
+ "phone_number_required" => "Il numero di telefono è richiesto",
"please_visit_my" => "Visitare il",
"position" => "Posizione",
"powered_by" => "Sviluppato da",
diff --git a/app/Language/km/Sales.php b/app/Language/km/Sales.php
index 80868cbc3..eec47d148 100644
--- a/app/Language/km/Sales.php
+++ b/app/Language/km/Sales.php
@@ -222,4 +222,5 @@ return [
"work_order_number_duplicate" => "",
"work_order_sent" => "",
"work_order_unsent" => "",
+ "sale_not_found" => "Sale not found",
];
diff --git a/app/Language/ml/Sales.php b/app/Language/ml/Sales.php
index b38f57446..3678be408 100644
--- a/app/Language/ml/Sales.php
+++ b/app/Language/ml/Sales.php
@@ -222,4 +222,5 @@ return [
"work_order_number_duplicate" => "",
"work_order_sent" => "",
"work_order_unsent" => "",
+ "sale_not_found" => "Sale not found",
];
diff --git a/app/Language/ta/Sales.php b/app/Language/ta/Sales.php
index 64591c078..c1611c31e 100644
--- a/app/Language/ta/Sales.php
+++ b/app/Language/ta/Sales.php
@@ -222,4 +222,5 @@ return [
"work_order_number_duplicate" => "Work Order Number must be unique.",
"work_order_sent" => "Work Order sent to",
"work_order_unsent" => "Work Order failed to be sent to",
+ "sale_not_found" => "விற்பனை காணப்படவில்லை",
];
diff --git a/app/Language/ur/Sales.php b/app/Language/ur/Sales.php
index 2e6af0951..f5e75dccc 100644
--- a/app/Language/ur/Sales.php
+++ b/app/Language/ur/Sales.php
@@ -222,4 +222,5 @@ return [
"work_order_number_duplicate" => "",
"work_order_sent" => "",
"work_order_unsent" => "",
+ "sale_not_found" => "Sale not found",
];
From 496c8a826200a7ccb83ec4357d0ca4c3382bffd3 Mon Sep 17 00:00:00 2001
From: Ollama
Date: Wed, 1 Apr 2026 09:16:24 +0000
Subject: [PATCH 05/13] Remove English fallbacks from non-English translations
Use empty strings for sale_not_found in Khmer, Malayalam, and Urdu
as these languages cannot be translated by this model.
---
app/Language/km/Sales.php | 2 +-
app/Language/ml/Sales.php | 2 +-
app/Language/ur/Sales.php | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/Language/km/Sales.php b/app/Language/km/Sales.php
index eec47d148..8fd15efb4 100644
--- a/app/Language/km/Sales.php
+++ b/app/Language/km/Sales.php
@@ -222,5 +222,5 @@ return [
"work_order_number_duplicate" => "",
"work_order_sent" => "",
"work_order_unsent" => "",
- "sale_not_found" => "Sale not found",
+ "sale_not_found" => "",
];
diff --git a/app/Language/ml/Sales.php b/app/Language/ml/Sales.php
index 3678be408..f8397f233 100644
--- a/app/Language/ml/Sales.php
+++ b/app/Language/ml/Sales.php
@@ -222,5 +222,5 @@ return [
"work_order_number_duplicate" => "",
"work_order_sent" => "",
"work_order_unsent" => "",
- "sale_not_found" => "Sale not found",
+ "sale_not_found" => "",
];
diff --git a/app/Language/ur/Sales.php b/app/Language/ur/Sales.php
index f5e75dccc..16f3d32e4 100644
--- a/app/Language/ur/Sales.php
+++ b/app/Language/ur/Sales.php
@@ -222,5 +222,5 @@ return [
"work_order_number_duplicate" => "",
"work_order_sent" => "",
"work_order_unsent" => "",
- "sale_not_found" => "Sale not found",
+ "sale_not_found" => "",
];
From 7180ec33e8b932ac648a15f3240672cdfc6991e3 Mon Sep 17 00:00:00 2001
From: Ollama
Date: Wed, 1 Apr 2026 09:23:00 +0000
Subject: [PATCH 06/13] Add Calendar.php translations for missing languages
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- es-MX: Spanish (Mexico) calendar translations
- nb: Norwegian Bokmål calendar translations
- he: Hebrew calendar translations
- ml: Malayalam calendar translations
- tl: Tagalog calendar translations
- ar-EG: Arabic (Egypt) calendar translations
- ka, lo, ur: Empty placeholders (cannot translate these languages)
---
app/Language/ar-EG/Calendar.php | 49 +++++++++++++++++++++++++++++++++
app/Language/es-MX/Calendar.php | 49 +++++++++++++++++++++++++++++++++
app/Language/he/Calendar.php | 49 +++++++++++++++++++++++++++++++++
app/Language/ka/Calendar.php | 49 +++++++++++++++++++++++++++++++++
app/Language/lo/Calendar.php | 49 +++++++++++++++++++++++++++++++++
app/Language/ml/Calendar.php | 49 +++++++++++++++++++++++++++++++++
app/Language/nb/Calendar.php | 49 +++++++++++++++++++++++++++++++++
app/Language/tl/Calendar.php | 49 +++++++++++++++++++++++++++++++++
app/Language/ur/Calendar.php | 49 +++++++++++++++++++++++++++++++++
9 files changed, 441 insertions(+)
create mode 100644 app/Language/ar-EG/Calendar.php
create mode 100644 app/Language/es-MX/Calendar.php
create mode 100644 app/Language/he/Calendar.php
create mode 100644 app/Language/ka/Calendar.php
create mode 100644 app/Language/lo/Calendar.php
create mode 100644 app/Language/ml/Calendar.php
create mode 100644 app/Language/nb/Calendar.php
create mode 100644 app/Language/tl/Calendar.php
create mode 100644 app/Language/ur/Calendar.php
diff --git a/app/Language/ar-EG/Calendar.php b/app/Language/ar-EG/Calendar.php
new file mode 100644
index 000000000..6041114d3
--- /dev/null
+++ b/app/Language/ar-EG/Calendar.php
@@ -0,0 +1,49 @@
+ "أحد",
+ "mo" => "اثنين",
+ "tu" => "ثلاثاء",
+ "we" => "أربعاء",
+ "th" => "خميس",
+ "fr" => "جمعة",
+ "sa" => "سبت",
+ "sun" => "الأحد",
+ "mon" => "الاثنين",
+ "tue" => "الثلاثاء",
+ "wed" => "الأربعاء",
+ "thu" => "الخميس",
+ "fri" => "الجمعة",
+ "sat" => "السبت",
+ "sunday" => "الأحد",
+ "monday" => "الاثنين",
+ "tuesday" => "الثلاثاء",
+ "wednesday" => "الأربعاء",
+ "thursday" => "الخميس",
+ "friday" => "الجمعة",
+ "saturday" => "السبت",
+ "jan" => "يناير",
+ "feb" => "فبراير",
+ "mar" => "مارس",
+ "apr" => "أبريل",
+ "may" => "مايو",
+ "jun" => "يونيو",
+ "jul" => "يوليو",
+ "aug" => "أغسطس",
+ "sep" => "سبتمبر",
+ "oct" => "أكتوبر",
+ "nov" => "نوفمبر",
+ "dec" => "ديسمبر",
+ "january" => "يناير",
+ "february" => "فبراير",
+ "march" => "مارس",
+ "april" => "أبريل",
+ "mayl" => "مايو",
+ "june" => "يونيو",
+ "july" => "يوليو",
+ "august" => "أغسطس",
+ "september" => "سبتمبر",
+ "october" => "أكتوبر",
+ "november" => "نوفمبر",
+ "december" => "ديسمبر",
+];
\ No newline at end of file
diff --git a/app/Language/es-MX/Calendar.php b/app/Language/es-MX/Calendar.php
new file mode 100644
index 000000000..e58476325
--- /dev/null
+++ b/app/Language/es-MX/Calendar.php
@@ -0,0 +1,49 @@
+ "Do",
+ "mo" => "Lu",
+ "tu" => "Ma",
+ "we" => "Mi",
+ "th" => "Ju",
+ "fr" => "Vi",
+ "sa" => "Sá",
+ "sun" => "Dom",
+ "mon" => "Lun",
+ "tue" => "Mar",
+ "wed" => "Mié",
+ "thu" => "Jue",
+ "fri" => "Vie",
+ "sat" => "Sáb",
+ "sunday" => "Domingo",
+ "monday" => "Lunes",
+ "tuesday" => "Martes",
+ "wednesday" => "Miércoles",
+ "thursday" => "Jueves",
+ "friday" => "Viernes",
+ "saturday" => "Sábado",
+ "jan" => "Ene",
+ "feb" => "Feb",
+ "mar" => "Mar",
+ "apr" => "Abr",
+ "may" => "May",
+ "jun" => "Jun",
+ "jul" => "Jul",
+ "aug" => "Ago",
+ "sep" => "Sep",
+ "oct" => "Oct",
+ "nov" => "Nov",
+ "dec" => "Dic",
+ "january" => "Enero",
+ "february" => "Febrero",
+ "march" => "Marzo",
+ "april" => "Abril",
+ "mayl" => "Mayo",
+ "june" => "Junio",
+ "july" => "Julio",
+ "august" => "Agosto",
+ "september" => "Septiembre",
+ "october" => "Octubre",
+ "november" => "Noviembre",
+ "december" => "Diciembre",
+];
\ No newline at end of file
diff --git a/app/Language/he/Calendar.php b/app/Language/he/Calendar.php
new file mode 100644
index 000000000..d300f5554
--- /dev/null
+++ b/app/Language/he/Calendar.php
@@ -0,0 +1,49 @@
+ "א",
+ "mo" => "ב",
+ "tu" => "ג",
+ "we" => "ד",
+ "th" => "ה",
+ "fr" => "ו",
+ "sa" => "ש",
+ "sun" => "יום א",
+ "mon" => "יום ב",
+ "tue" => "יום ג",
+ "wed" => "יום ד",
+ "thu" => "יום ה",
+ "fri" => "יום ו",
+ "sat" => "שבת",
+ "sunday" => "יום ראשון",
+ "monday" => "יום שני",
+ "tuesday" => "יום שלישי",
+ "wednesday" => "יום רביעי",
+ "thursday" => "יום חמישי",
+ "friday" => "יום שישי",
+ "saturday" => "יום שבת",
+ "jan" => "ינו",
+ "feb" => "פבר",
+ "mar" => "מרץ",
+ "apr" => "אפר",
+ "may" => "מאי",
+ "jun" => "יונ",
+ "jul" => "יול",
+ "aug" => "אוג",
+ "sep" => "ספט",
+ "oct" => "אוק",
+ "nov" => "נוב",
+ "dec" => "דצמ",
+ "january" => "ינואר",
+ "february" => "פברואר",
+ "march" => "מרץ",
+ "april" => "אפריל",
+ "mayl" => "מאי",
+ "june" => "יוני",
+ "july" => "יולי",
+ "august" => "אוגוסט",
+ "september" => "ספטמבר",
+ "october" => "אוקטובר",
+ "november" => "נובמבר",
+ "december" => "דצמבר",
+];
\ No newline at end of file
diff --git a/app/Language/ka/Calendar.php b/app/Language/ka/Calendar.php
new file mode 100644
index 000000000..b3c9c5d15
--- /dev/null
+++ b/app/Language/ka/Calendar.php
@@ -0,0 +1,49 @@
+ "",
+ "mo" => "",
+ "tu" => "",
+ "we" => "",
+ "th" => "",
+ "fr" => "",
+ "sa" => "",
+ "sun" => "",
+ "mon" => "",
+ "tue" => "",
+ "wed" => "",
+ "thu" => "",
+ "fri" => "",
+ "sat" => "",
+ "sunday" => "",
+ "monday" => "",
+ "tuesday" => "",
+ "wednesday" => "",
+ "thursday" => "",
+ "friday" => "",
+ "saturday" => "",
+ "jan" => "",
+ "feb" => "",
+ "mar" => "",
+ "apr" => "",
+ "may" => "",
+ "jun" => "",
+ "jul" => "",
+ "aug" => "",
+ "sep" => "",
+ "oct" => "",
+ "nov" => "",
+ "dec" => "",
+ "january" => "",
+ "february" => "",
+ "march" => "",
+ "april" => "",
+ "mayl" => "",
+ "june" => "",
+ "july" => "",
+ "august" => "",
+ "september" => "",
+ "october" => "",
+ "november" => "",
+ "december" => "",
+];
\ No newline at end of file
diff --git a/app/Language/lo/Calendar.php b/app/Language/lo/Calendar.php
new file mode 100644
index 000000000..b3c9c5d15
--- /dev/null
+++ b/app/Language/lo/Calendar.php
@@ -0,0 +1,49 @@
+ "",
+ "mo" => "",
+ "tu" => "",
+ "we" => "",
+ "th" => "",
+ "fr" => "",
+ "sa" => "",
+ "sun" => "",
+ "mon" => "",
+ "tue" => "",
+ "wed" => "",
+ "thu" => "",
+ "fri" => "",
+ "sat" => "",
+ "sunday" => "",
+ "monday" => "",
+ "tuesday" => "",
+ "wednesday" => "",
+ "thursday" => "",
+ "friday" => "",
+ "saturday" => "",
+ "jan" => "",
+ "feb" => "",
+ "mar" => "",
+ "apr" => "",
+ "may" => "",
+ "jun" => "",
+ "jul" => "",
+ "aug" => "",
+ "sep" => "",
+ "oct" => "",
+ "nov" => "",
+ "dec" => "",
+ "january" => "",
+ "february" => "",
+ "march" => "",
+ "april" => "",
+ "mayl" => "",
+ "june" => "",
+ "july" => "",
+ "august" => "",
+ "september" => "",
+ "october" => "",
+ "november" => "",
+ "december" => "",
+];
\ No newline at end of file
diff --git a/app/Language/ml/Calendar.php b/app/Language/ml/Calendar.php
new file mode 100644
index 000000000..1da89214d
--- /dev/null
+++ b/app/Language/ml/Calendar.php
@@ -0,0 +1,49 @@
+ "ഞാ",
+ "mo" => "തി",
+ "tu" => "ചൊ",
+ "we" => "ബു",
+ "th" => "വ്യാ",
+ "fr" => "വെ",
+ "sa" => "ശ",
+ "sun" => "ഞായർ",
+ "mon" => "തിങ്കൾ",
+ "tue" => "ചൊവ്വ",
+ "wed" => "ബുധൻ",
+ "thu" => "വ്യാഴം",
+ "fri" => "വെള്ളി",
+ "sat" => "ശനി",
+ "sunday" => "ഞായറാഴ്ച",
+ "monday" => "തിങ്കളാഴ്ച",
+ "tuesday" => "ചൊവ്വാഴ്ച",
+ "wednesday" => "ബുധനാഴ്ച",
+ "thursday" => "വ്യാഴാഴ്ച",
+ "friday" => "വെള്ളിയാഴ്ച",
+ "saturday" => "ശനിയാഴ്ച",
+ "jan" => "ജനു",
+ "feb" => "ഫെബ്രു",
+ "mar" => "മാർ",
+ "apr" => "ഏപ്രി",
+ "may" => "മേയ്",
+ "jun" => "ജൂൺ",
+ "jul" => "ജൂലൈ",
+ "aug" => "ആഗ",
+ "sep" => "സെപ്റ്റം",
+ "oct" => "ഒക്ടോ",
+ "nov" => "നവം",
+ "dec" => "ഡിസം",
+ "january" => "ജനുവരി",
+ "february" => "ഫെബ്രുവരി",
+ "march" => "മാർച്ച്",
+ "april" => "ഏപ്രിൽ",
+ "mayl" => "മേയ്",
+ "june" => "ജൂൺ",
+ "july" => "ജൂലൈ",
+ "august" => "ആഗസ്റ്റ്",
+ "september" => "സെപ്റ്റംബർ",
+ "october" => "ഒക്ടോബർ",
+ "november" => "നവംബർ",
+ "december" => "ഡിസംബർ",
+];
\ No newline at end of file
diff --git a/app/Language/nb/Calendar.php b/app/Language/nb/Calendar.php
new file mode 100644
index 000000000..bb7e706b2
--- /dev/null
+++ b/app/Language/nb/Calendar.php
@@ -0,0 +1,49 @@
+ "Sø",
+ "mo" => "Ma",
+ "tu" => "Ti",
+ "we" => "On",
+ "th" => "To",
+ "fr" => "Fr",
+ "sa" => "Lø",
+ "sun" => "Søn",
+ "mon" => "Man",
+ "tue" => "Tir",
+ "wed" => "Ons",
+ "thu" => "Tor",
+ "fri" => "Fre",
+ "sat" => "Lør",
+ "sunday" => "Søndag",
+ "monday" => "Mandag",
+ "tuesday" => "Tirsdag",
+ "wednesday" => "Onsdag",
+ "thursday" => "Torsdag",
+ "friday" => "Fredag",
+ "saturday" => "Lørdag",
+ "jan" => "Jan",
+ "feb" => "Feb",
+ "mar" => "Mar",
+ "apr" => "Apr",
+ "may" => "Mai",
+ "jun" => "Jun",
+ "jul" => "Jul",
+ "aug" => "Aug",
+ "sep" => "Sep",
+ "oct" => "Okt",
+ "nov" => "Nov",
+ "dec" => "Des",
+ "january" => "Januar",
+ "february" => "Februar",
+ "march" => "Mars",
+ "april" => "April",
+ "mayl" => "Mai",
+ "june" => "Juni",
+ "july" => "Juli",
+ "august" => "August",
+ "september" => "September",
+ "october" => "Oktober",
+ "november" => "November",
+ "december" => "Desember",
+];
\ No newline at end of file
diff --git a/app/Language/tl/Calendar.php b/app/Language/tl/Calendar.php
new file mode 100644
index 000000000..c73063d2d
--- /dev/null
+++ b/app/Language/tl/Calendar.php
@@ -0,0 +1,49 @@
+ "ఆ",
+ "mo" => "సో",
+ "tu" => "మం",
+ "we" => "బు",
+ "th" => "గు",
+ "fr" => "శు",
+ "sa" => "శ",
+ "sun" => "ఆది",
+ "mon" => "సోమ",
+ "tue" => "మంగళ",
+ "wed" => "బుధ",
+ "thu" => "గురు",
+ "fri" => "శుక్ర",
+ "sat" => "శని",
+ "sunday" => "ఆదివారం",
+ "monday" => "సోమవారం",
+ "tuesday" => "మంగళవారం",
+ "wednesday" => "బుధవారం",
+ "thursday" => "గురువారం",
+ "friday" => "శుక్రవారం",
+ "saturday" => "శనివారం",
+ "jan" => "జన",
+ "feb" => "ఫిబ్ర",
+ "mar" => "మార్",
+ "apr" => "ఏప్రి",
+ "may" => "మే",
+ "jun" => "జూన్",
+ "jul" => "జూలై",
+ "aug" => "ఆగ",
+ "sep" => "సెప్టెం",
+ "oct" => "అక్టో",
+ "nov" => "నవం",
+ "dec" => "డిసెం",
+ "january" => "జనవరి",
+ "february" => "ఫిబ్రవరి",
+ "march" => "మార్చి",
+ "april" => "ఏప్రిల్",
+ "mayl" => "మే",
+ "june" => "జూన్",
+ "july" => "జూలై",
+ "august" => "ఆగస్టు",
+ "september" => "సెప్టెంబర్",
+ "october" => "అక్టోబర్",
+ "november" => "నవంబర్",
+ "december" => "డిసెంబర్",
+];
\ No newline at end of file
diff --git a/app/Language/ur/Calendar.php b/app/Language/ur/Calendar.php
new file mode 100644
index 000000000..b3c9c5d15
--- /dev/null
+++ b/app/Language/ur/Calendar.php
@@ -0,0 +1,49 @@
+ "",
+ "mo" => "",
+ "tu" => "",
+ "we" => "",
+ "th" => "",
+ "fr" => "",
+ "sa" => "",
+ "sun" => "",
+ "mon" => "",
+ "tue" => "",
+ "wed" => "",
+ "thu" => "",
+ "fri" => "",
+ "sat" => "",
+ "sunday" => "",
+ "monday" => "",
+ "tuesday" => "",
+ "wednesday" => "",
+ "thursday" => "",
+ "friday" => "",
+ "saturday" => "",
+ "jan" => "",
+ "feb" => "",
+ "mar" => "",
+ "apr" => "",
+ "may" => "",
+ "jun" => "",
+ "jul" => "",
+ "aug" => "",
+ "sep" => "",
+ "oct" => "",
+ "nov" => "",
+ "dec" => "",
+ "january" => "",
+ "february" => "",
+ "march" => "",
+ "april" => "",
+ "mayl" => "",
+ "june" => "",
+ "july" => "",
+ "august" => "",
+ "september" => "",
+ "october" => "",
+ "november" => "",
+ "december" => "",
+];
\ No newline at end of file
From f74f286a51842a96faad243486dcf0564481e544 Mon Sep 17 00:00:00 2001
From: Ollama
Date: Thu, 19 Mar 2026 21:34:12 +0000
Subject: [PATCH 07/13] feat: migrate CI from Travis to GitHub Actions with
enhancements
- Convert Travis CI configuration to GitHub Actions workflows
- Add multi-arch Docker builds (amd64/arm64)
- Implement initial schema migration for fresh database installs
- Add multi-attribute search with AND logic and sort by attribute columns
- Address various PR review feedback and formatting fixes
---
.github/workflows/README.md | 61 ++
.github/workflows/build-release.yml | 218 +++++
.github/workflows/codeql-analysis.yml | 71 --
.github/workflows/phpunit.yml | 4 -
.travis.yml | 54 --
Dockerfile | 13 -
INSTALL.md | 13 +-
README.md | 8 +-
.../20170501000000_initial_schema.php | 60 ++
.../Migrations/sqlscripts/initial_schema.sql | 877 ++++++++++++++++++
docker-compose.dev.yml | 1 -
docker-compose.test.yml | 21 -
docker-compose.yml | 3 -
docker/docker-mysql.yml | 2 -
gulpfile.js | 28 +-
tests/Libraries/Token_libTest.php | 2 +-
16 files changed, 1229 insertions(+), 207 deletions(-)
create mode 100644 .github/workflows/README.md
create mode 100644 .github/workflows/build-release.yml
delete mode 100644 .github/workflows/codeql-analysis.yml
delete mode 100644 .travis.yml
create mode 100644 app/Database/Migrations/20170501000000_initial_schema.php
create mode 100644 app/Database/Migrations/sqlscripts/initial_schema.sql
delete mode 100644 docker-compose.test.yml
diff --git a/.github/workflows/README.md b/.github/workflows/README.md
new file mode 100644
index 000000000..ff51f5276
--- /dev/null
+++ b/.github/workflows/README.md
@@ -0,0 +1,61 @@
+# GitHub Actions
+
+This document describes the CI/CD workflows for OSPOS.
+
+## Build and Release Workflow (`.github/workflows/build-release.yml`)
+
+### Build Process
+- Setup PHP 8.2 with required extensions
+- Setup Node.js 20
+- Install composer dependencies
+- Install npm dependencies
+- Build frontend assets with Gulp
+
+### Docker Images
+- Build and push `opensourcepos` Docker image for multiple architectures (linux/amd64, linux/arm64)
+- On master: tagged with version and `latest`
+- On other branches: tagged with version only
+- Pushed to Docker Hub
+
+### Releases
+- Create distribution archives (tar.gz, zip)
+- Create/update GitHub "unstable" release on master branch only
+
+## Required Secrets
+
+To use this workflow, you need to add the following secrets to your repository:
+
+1. **DOCKER_USERNAME** - Docker Hub username for pushing images
+2. **DOCKER_PASSWORD** - Docker Hub password/token for pushing images
+
+### How to add secrets
+
+1. Go to your repository on GitHub
+2. Click **Settings** → **Secrets and variables** → **Actions**
+3. Click **New repository secret**
+4. Add `DOCKER_USERNAME` and `DOCKER_PASSWORD`
+
+The `GITHUB_TOKEN` is automatically provided by GitHub Actions.
+
+## Workflow Triggers
+
+- **Push to master** - Runs build, Docker push (with `latest` tag), and release
+- **Push to other branches** - Runs build and Docker push (version tag only)
+- **Push tags** - Runs build and Docker push (version tag only)
+- **Pull requests** - Runs build only (PHPUnit tests run in parallel via phpunit.yml)
+
+## Existing Workflows
+
+This repository also has these workflows:
+- `.github/workflows/main.yml` - PHP linting with PHP-CS-Fixer
+- `.github/workflows/phpunit.yml` - PHPUnit tests (runs on all PHP versions 8.1-8.4)
+- `.github/workflows/php-linter.yml` - PHP linting
+
+## Testing
+
+PHPUnit tests are run separately via `.github/workflows/phpunit.yml` on every push and pull request, testing against PHP 8.1, 8.2, 8.3, and 8.4.
+
+To test the build workflow:
+1. Add the required secrets
+2. Push to master or create a PR
+3. Monitor the Actions tab in GitHub
\ No newline at end of file
diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml
new file mode 100644
index 000000000..d7433d35c
--- /dev/null
+++ b/.github/workflows/build-release.yml
@@ -0,0 +1,218 @@
+name: Build and Release
+
+on:
+ push:
+ branches:
+ - master
+ tags:
+ - '*'
+ pull_request:
+ branches:
+ - master
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ name: Build
+ runs-on: ubuntu-22.04
+
+ outputs:
+ version: ${{ steps.version.outputs.version }}
+ version-tag: ${{ steps.version.outputs.version-tag }}
+ short-sha: ${{ steps.version.outputs.short-sha }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.2'
+ extensions: intl, mbstring, mysqli, gd, bcmath, zip
+ coverage: none
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+
+ - name: Get composer cache directory
+ run: echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v4
+ with:
+ path: ${{ env.COMPOSER_CACHE_FILES_DIR }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-composer-
+
+ - name: Get npm cache directory
+ run: echo "NPM_CACHE_DIR=$(npm config get cache)" >> $GITHUB_ENV
+
+ - name: Cache npm dependencies
+ uses: actions/cache@v4
+ with:
+ path: ${{ env.NPM_CACHE_DIR }}
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-node-
+
+ - name: Install composer dependencies
+ run: composer install --no-dev --optimize-autoloader
+
+ - name: Install npm dependencies
+ run: npm ci
+
+ - name: Install gulp globally
+ run: npm install -g gulp-cli
+
+ - name: Get version info
+ id: version
+ run: |
+ VERSION=$(grep "application_version" app/Config/App.php | sed "s/.*= '\(.*\)';/\1/g")
+ BRANCH=$(echo "${GITHUB_REF#refs/heads/}" | sed 's/feature\///')
+ TAG=$(echo "${GITHUB_TAG:-$BRANCH}" | tr '/' '-')
+ SHORT_SHA=$(git rev-parse --short=6 HEAD)
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
+ echo "version-tag=$VERSION-$BRANCH-$SHORT_SHA" >> $GITHUB_OUTPUT
+ echo "short-sha=$SHORT_SHA" >> $GITHUB_OUTPUT
+ echo "branch=$BRANCH" >> $GITHUB_OUTPUT
+ env:
+ GITHUB_TAG: ${{ github.ref_name }}
+
+ - name: Create .env file
+ run: |
+ cp .env.example .env
+ sed -i 's/production/development/g' .env
+
+ - name: Update commit hash
+ run: |
+ SHORT_SHA="${{ steps.version.outputs.short-sha }}"
+ sed -i "s/commit_sha1 = 'dev'/commit_sha1 = '$SHORT_SHA'/g" app/Config/OSPOS.php
+
+ - name: Build frontend assets
+ run: npm run build
+
+ - name: Create distribution archives
+ run: |
+ set -euo pipefail
+ gulp compress
+ VERSION="${{ steps.version.outputs.version }}"
+ SHORT_SHA="${{ steps.version.outputs.short-sha }}"
+ mv dist/opensourcepos.tar "dist/opensourcepos.$VERSION.$SHORT_SHA.tar"
+ mv dist/opensourcepos.zip "dist/opensourcepos.$VERSION.$SHORT_SHA.zip"
+
+ - name: Upload build artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: dist-${{ steps.version.outputs.short-sha }}
+ path: dist/
+ retention-days: 7
+
+ - name: Upload build context for Docker
+ uses: actions/upload-artifact@v4
+ with:
+ name: build-context-${{ steps.version.outputs.short-sha }}
+ path: |
+ .
+ !.git
+ !node_modules
+ retention-days: 1
+
+ docker:
+ name: Build Docker Image
+ runs-on: ubuntu-22.04
+ needs: build
+ if: github.event_name == 'push'
+
+ steps:
+ - name: Download build context
+ uses: actions/download-artifact@v4
+ with:
+ name: build-context-${{ needs.build.outputs.short-sha }}
+ path: .
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v3
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_PASSWORD }}
+
+ - name: Determine Docker tags
+ id: tags
+ run: |
+ BRANCH=$(echo "${GITHUB_REF#refs/heads/}" | tr '/' '-')
+ if [ "$BRANCH" = "master" ]; then
+ echo "tags=${{ secrets.DOCKER_USERNAME }}/opensourcepos:${{ needs.build.outputs.version-tag }},${{ secrets.DOCKER_USERNAME }}/opensourcepos:latest" >> $GITHUB_OUTPUT
+ else
+ echo "tags=${{ secrets.DOCKER_USERNAME }}/opensourcepos:${{ needs.build.outputs.version-tag }}" >> $GITHUB_OUTPUT
+ fi
+ env:
+ GITHUB_REF: ${{ github.ref }}
+
+ - name: Build and push Docker images
+ uses: docker/build-push-action@v5
+ with:
+ context: .
+ target: ospos
+ platforms: linux/amd64,linux/arm64
+ push: true
+ tags: ${{ steps.tags.outputs.tags }}
+
+ release:
+ name: Create Release
+ needs: build
+ runs-on: ubuntu-22.04
+ if: github.event_name == 'push' && github.ref == 'refs/heads/master'
+ permissions:
+ contents: write
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Download build artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: dist-${{ needs.build.outputs.short-sha }}
+ path: dist/
+
+ - name: Get version info
+ id: version
+ run: |
+ VERSION="${{ needs.build.outputs.version }}"
+ SHORT_SHA=$(git rev-parse --short=6 HEAD)
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
+ echo "short-sha=$SHORT_SHA" >> $GITHUB_OUTPUT
+
+ - name: Create/Update unstable release
+ uses: softprops/action-gh-release@v2
+ with:
+ tag_name: unstable
+ name: Unstable OpenSourcePOS
+ body: |
+ This is a build of the latest master which might contain bugs. Use at your own risk.
+
+ Check the releases section for the latest official release.
+ files: |
+ dist/opensourcepos.${{ steps.version.outputs.version }}.${{ steps.version.outputs.short-sha }}.zip
+ prerelease: true
+ draft: false
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
deleted file mode 100644
index 6218fde3a..000000000
--- a/.github/workflows/codeql-analysis.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-# For most projects, this workflow file will not need changing; you simply need
-# to commit it to your repository.
-#
-# You may wish to alter this file to override the set of languages analyzed,
-# or to provide custom queries or build logic.
-#
-# ******** NOTE ********
-# We have attempted to detect the languages in your repository. Please check
-# the `language` matrix defined below to confirm you have the correct set of
-# supported CodeQL languages.
-#
-name: "CodeQL"
-
-on:
- push:
- branches: [ master ]
- pull_request:
- # The branches below must be a subset of the branches above
- branches: [ master ]
- schedule:
- - cron: '21 12 * * 3'
-
-jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
- permissions:
- actions: read
- contents: read
- security-events: write
-
- strategy:
- fail-fast: false
- matrix:
- language: [ 'javascript' ]
- # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
- # Learn more:
- # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
-
- steps:
- - name: Checkout repository
- uses: actions/checkout@v2
-
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v1
- with:
- languages: ${{ matrix.language }}
- # If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
- # Prefix the list here with "+" to use these queries and those in the config file.
- # queries: ./path/to/local/query, your-org/your-repo/queries@main
-
- # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
- # If this step fails, then you should remove it and run the build manually (see below)
- - name: Autobuild
- uses: github/codeql-action/autobuild@v1
-
- # ℹ️ Command-line programs to run using the OS shell.
- # 📚 https://git.io/JvXDl
-
- # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
- # and modify them (or add more) to build your code if your project
- # uses a compiled language
-
- #- run: |
- # make bootstrap
- # make release
-
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml
index fe7b3ff48..2198acaf8 100644
--- a/.github/workflows/phpunit.yml
+++ b/.github/workflows/phpunit.yml
@@ -69,9 +69,6 @@ jobs:
- name: Install npm dependencies
run: npm install
- - name: Build database.sql
- run: npm run gulp build-database
-
- name: Start MariaDB
run: |
docker run -d --name mysql \
@@ -79,7 +76,6 @@ jobs:
-e MYSQL_DATABASE=ospos \
-e MYSQL_USER=admin \
-e MYSQL_PASSWORD=pointofsale \
- -v $PWD/app/Database/database.sql:/docker-entrypoint-initdb.d/database.sql \
-p 3306:3306 \
mariadb:10.5
# Wait for MariaDB to be ready
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 908983cfd..000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,54 +0,0 @@
-sudo: required
-
-branches:
- except:
- - unstable
- - weblate
-services:
- - docker
-
-dist: jammy
-language: node_js
-node_js:
- - 20
-script:
- - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
- - docker run --rm -u $(id -u) -v $(pwd):/app opensourcepos/composer:ci4 composer install
- - version=$(grep application_version app/Config/App.php | sed "s/.*=\s'\(.*\)';/\1/g")
- - cp .env.example .env && sed -i 's/production/development/g' .env
- - sed -i "s/commit_sha1 = 'dev'/commit_sha1 = '$rev'/g" app/Config/OSPOS.php
- - echo "$version-$branch-$rev"
- - npm version "$version-$branch-$rev" --force || true
- - sed -i 's/opensourcepos.tar.gz/opensourcepos.$version.tgz/g' package.json
- - npm ci && npm install -g gulp && npm run build
- - docker build . --target ospos -t ospos
- - docker build . --target ospos_test -t ospos_test
- - docker run --rm ospos_test /app/vendor/bin/phpunit --testdox
- - docker build app/Database/ -t "jekkos/opensourcepos:sql-$TAG"
-env:
- global:
- - BRANCH=$(echo ${TRAVIS_BRANCH} | sed s/feature\\///)
- - TAG=$(echo "${TRAVIS_TAG:-$BRANCH}" | tr '/' '-')
- - date=`date +%Y%m%d%H%M%S` && branch=${TRAVIS_BRANCH} && rev=`git rev-parse --short=6 HEAD`
-after_success:
- - docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD" && docker tag "ospos:latest"
- "jekkos/opensourcepos:$TAG" && docker push "jekkos/opensourcepos:$TAG" && docker push "jekkos/opensourcepos:sql-$TAG"
- - gulp compress
- - mv dist/opensourcepos.tar.gz "dist/opensourcepos.$version.$rev.tgz"
- - mv dist/opensourcepos.zip "dist/opensourcepos.$version.$rev.zip"
-deploy:
- - provider: releases
- edge: true
- file: dist/opensourcepos.$version.$rev.zip
- name: "Unstable OpensourcePos"
- overwrite: true
- release_notes: "This is a build of the latest master which might contain bugs. Use at your own risk. Check releases section for the latest official release"
- prerelease: true
- tag_name: unstable
- user: jekkos
-
- api_key:
- secure: "KOukL8IFf/uL/BjMyCSKjf2vylydjcWqgEx0eMqFCg3nZ4ybMaOwPORRthIfyT72/FvGX/aoxxEn0uR/AEtb+hYQXHmNS+kZdX72JCe8LpGuZ7FJ5X+Eo9mhJcsmS+smd1sC95DySSc/GolKPo+0WtJYONY/xGCLxm+9Ay4HREg="
-
- on:
- branch: master
diff --git a/Dockerfile b/Dockerfile
index 376b0834d..ca1b5a46c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -11,19 +11,6 @@ COPY . /app
RUN ln -s /app/*[^public] /var/www && rm -rf /var/www/html && ln -nsf /app/public /var/www/html
RUN chmod -R 770 /app/writable/uploads /app/writable/logs /app/writable/cache && chown -R www-data:www-data /app
-FROM ospos AS ospos_test
-
-COPY --from=composer /usr/bin/composer /usr/bin/composer
-
-RUN apt-get install -y libzip-dev wget git
-RUN wget https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh -O /bin/wait-for-it.sh && chmod +x /bin/wait-for-it.sh
-RUN docker-php-ext-install zip
-RUN composer install -d/app
-#RUN sed -i 's/backupGlobals="true"/backupGlobals="false"/g' /app/tests/phpunit.xml
-WORKDIR /app/tests
-
-CMD ["/app/vendor/phpunit/phpunit/phpunit", "/app/test/helpers"]
-
FROM ospos AS ospos_dev
ARG USERID
diff --git a/INSTALL.md b/INSTALL.md
index df08c0afc..b63ff893f 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -38,20 +38,21 @@ FORCE_HTTPS = true
## Local install
-First of all, if you're seeing the message `system folder missing` after launching your browser, or cannot find `database.sql`, that most likely means you have cloned the repository and have not built the project. To build the project from a source commit point instead of from an official release check out [Building OSPOS](BUILD.md). Otherwise, continue with the following steps.
+First of all, if you're seeing the message `system folder missing` after launching your browser, that most likely means you have cloned the repository and have not built the project. To build the project from a source commit point instead of from an official release check out [Building OSPOS](BUILD.md). Otherwise, continue with the following steps.
1. Download the a [pre-release for a specific branch](https://github.com/opensourcepos/opensourcepos/releases) or the latest stable [from GitHub here](https://github.com/opensourcepos/opensourcepos/releases). A repository clone will not work unless know how to build the project.
2. Create/locate a new MySQL database to install Open Source Point of Sale into.
-3. Execute the file `app/Database/database.sql` to create the tables needed.
-4. Unzip and upload Open Source Point of Sale files to the web-server.
-5. Open `.env` file and modify credentials to connect to your database if needed. (First copy .env.example to .env and update)
+3. Unzip and upload Open Source Point of Sale files to the web-server.
+4. If `.env` does not exist, copy `.env.example` to `.env`.
+5. Open `.env` and modify credentials to connect to your database if needed.
+6. The database schema will be automatically created when you first access the application. Migrations run automatically on fresh installs.
7. Go to your install `public` dir via the browser.
8. Log in using
- Username: admin
- Password: pointofsale
9. If everything works, then set the `CI_ENVIRONMENT` variable to `production` in the .env file
-9. Enjoy!
-10. Oops, an issue? Please make sure you read the FAQ, wiki page, and you checked open and closed issues on GitHub. PHP `display_errors` is disabled by default. Create an` app/Config/.env` file from the `.env.example` to enable it in a development environment.
+10. Enjoy!
+11. Oops, an issue? Please make sure you read the FAQ, wiki page, and you checked open and closed issues on GitHub. PHP `display_errors` is disabled by default. Create an` app/Config/.env` file from the `.env.example` to enable it in a development environment.
## Local install using Docker
diff --git a/README.md b/README.md
index 755c73f60..1a46a4386 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
-
+
@@ -137,7 +137,7 @@ Any person or company found breaching the license agreement might find a bunch o
## 🙏 Credits
-|
DigitalOcean
| JetBrains
| Travis CI
|
+| DigitalOcean
| JetBrains
| GitHub
|
| --- | --- | --- |
-| 
| 
| 
|
-| Many thanks to [DigitalOcean](https://www.digitalocean.com) for providing the project with hosting credits. | Many thanks to [JetBrains](https://www.jetbrains.com/) for providing a free license of [IntelliJ IDEA](https://www.jetbrains.com/idea/) to kindly support the development of OSPOS. | Many thanks to [Travis CI](https://www.travis-ci.com/) for providing a free continuous integration service for open source projects. |
+| 
| 
| 
|
+| Many thanks to [DigitalOcean](https://www.digitalocean.com) for providing the project with hosting credits. | Many thanks to [JetBrains](https://www.jetbrains.com/) for providing a free license of [IntelliJ IDEA](https://www.jetbrains.com/idea/) to kindly support the development of OSPOS. | Many thanks to [GitHub](https://github.com) for providing free continuous integration via GitHub Actions for open-source projects. |
diff --git a/app/Database/Migrations/20170501000000_initial_schema.php b/app/Database/Migrations/20170501000000_initial_schema.php
new file mode 100644
index 000000000..0424dba03
--- /dev/null
+++ b/app/Database/Migrations/20170501000000_initial_schema.php
@@ -0,0 +1,60 @@
+db->listTables();
+
+ // Check for a core application table, not just migrations table
+ foreach ($tables as $table) {
+ // Strip prefix if present for comparison
+ $tableName = str_replace($this->db->getPrefix(), '', $table);
+ if (in_array($tableName, ['app_config', 'items', 'employees', 'people'])) {
+ // Database already populated - skip initial schema
+ // This is an existing installation upgrading from older version
+ return;
+ }
+ }
+
+ // Fresh install - load initial schema
+ helper('migration');
+ execute_script(APPPATH . 'Database/Migrations/sqlscripts/initial_schema.sql');
+ }
+
+ /**
+ * Revert a migration step.
+ * Cannot revert initial schema - would lose all data.
+ */
+ public function down(): void
+ {
+ // Cannot safely revert initial schema
+ // Would require dropping all tables which would lose all data
+ $this->db->query('SET FOREIGN_KEY_CHECKS = 0');
+
+ foreach ($this->db->listTables() as $table) {
+ $this->db->query('DROP TABLE IF EXISTS `' . $table . '`');
+ }
+
+ $this->db->query('SET FOREIGN_KEY_CHECKS = 1');
+ }
+}
\ No newline at end of file
diff --git a/app/Database/Migrations/sqlscripts/initial_schema.sql b/app/Database/Migrations/sqlscripts/initial_schema.sql
new file mode 100644
index 000000000..0823793a5
--- /dev/null
+++ b/app/Database/Migrations/sqlscripts/initial_schema.sql
@@ -0,0 +1,877 @@
+
+--
+-- Table structure for table `ospos_app_config`
+--
+
+CREATE TABLE `ospos_app_config` (
+ `key` varchar(50) NOT NULL,
+ `value` varchar(500) NOT NULL,
+ PRIMARY KEY (`key`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_app_config`
+--
+
+INSERT INTO `ospos_app_config` (`key`, `value`) VALUES
+ ('address', '123 Nowhere street'),
+ ('company', 'Open Source Point of Sale'),
+ ('default_tax_rate', '8'),
+ ('email', 'changeme@example.com'),
+ ('fax', ''),
+ ('phone', '555-555-5555'),
+ ('return_policy', 'Test'),
+ ('timezone', 'America/New_York'),
+ ('website', ''),
+ ('company_logo', ''),
+ ('tax_included', '0'),
+ ('barcode_content', 'id'),
+ ('barcode_type', 'Code39'),
+ ('barcode_width', '250'),
+ ('barcode_height', '50'),
+ ('barcode_quality', '100'),
+ ('barcode_font', 'Arial'),
+ ('barcode_font_size', '10'),
+ ('barcode_first_row', 'category'),
+ ('barcode_second_row', 'item_code'),
+ ('barcode_third_row', 'unit_price'),
+ ('barcode_num_in_row', '2'),
+ ('barcode_page_width', '100'),
+ ('barcode_page_cellspacing', '20'),
+ ('barcode_generate_if_empty', '0'),
+ ('receipt_show_taxes', '0'),
+ ('receipt_show_total_discount', '1'),
+ ('receipt_show_description', '1'),
+ ('receipt_show_serialnumber', '1'),
+ ('invoice_enable', '1'),
+ ('recv_invoice_format', '$CO'),
+ ('sales_invoice_format', '$CO'),
+ ('invoice_email_message', 'Dear $CU, In attachment the receipt for sale $INV'),
+ ('invoice_default_comments', 'This is a default comment'),
+ ('print_silently', '1'),
+ ('print_header', '0'),
+ ('print_footer', '0'),
+ ('print_top_margin', '0'),
+ ('print_left_margin', '0'),
+ ('print_bottom_margin', '0'),
+ ('print_right_margin', '0'),
+ ('default_sales_discount', '0'),
+ ('lines_per_page', '25'),
+ ('dateformat', 'm/d/Y'),
+ ('timeformat', 'H:i:s'),
+ ('currency_symbol', '$'),
+ ('number_locale', 'en_US'),
+ ('thousands_separator', '1'),
+ ('currency_decimals', '2'),
+ ('tax_decimals', '2'),
+ ('quantity_decimals', '0'),
+ ('country_codes', 'us'),
+ ('msg_msg', ''),
+ ('msg_uid', ''),
+ ('msg_src', ''),
+ ('msg_pwd', ''),
+ ('notify_horizontal_position', 'center'),
+ ('notify_vertical_position', 'bottom'),
+ ('payment_options_order', 'cashdebitcredit'),
+ ('protocol', 'mail'),
+ ('mailpath', '/usr/sbin/sendmail'),
+ ('smtp_port', '465'),
+ ('smtp_timeout', '5'),
+ ('smtp_crypto', 'ssl'),
+ ('receipt_template', 'receipt_default'),
+ ('theme', 'flatly'),
+ ('statistics', '1'),
+ ('language', 'english'),
+ ('language_code', 'en');
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_customers`
+--
+
+CREATE TABLE `ospos_customers` (
+ `person_id` int(10) NOT NULL,
+ `company_name` varchar(255) DEFAULT NULL,
+ `account_number` varchar(255) DEFAULT NULL,
+ `taxable` int(1) NOT NULL DEFAULT '1',
+ `discount_percent` decimal(15,2) NOT NULL DEFAULT '0',
+ `deleted` int(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY `person_id` (`person_id`),
+ UNIQUE KEY `account_number` (`account_number`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_customers`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_employees`
+--
+
+CREATE TABLE `ospos_employees` (
+ `username` varchar(255) NOT NULL,
+ `password` varchar(255) NOT NULL,
+ `person_id` int(10) NOT NULL,
+ `deleted` int(1) NOT NULL DEFAULT '0',
+ `hash_version` int(1) NOT NULL DEFAULT '2',
+ PRIMARY KEY `person_id` (`person_id`),
+ UNIQUE KEY `username` (`username`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_employees`
+--
+
+INSERT INTO `ospos_employees` (`username`, `password`, `person_id`, `deleted`, `hash_version`) VALUES
+ ('admin', '$2y$10$vJBSMlD02EC7ENSrKfVQXuvq9tNRHMtcOA8MSK2NYS748HHWm.gcG', 1, 0, 2);
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_giftcards`
+--
+
+CREATE TABLE `ospos_giftcards` (
+ `record_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `giftcard_id` int(11) NOT NULL AUTO_INCREMENT,
+ `giftcard_number` int(10) NOT NULL,
+ `value` decimal(15,2) NOT NULL,
+ `deleted` int(1) NOT NULL DEFAULT '0',
+ `person_id` INT(10) DEFAULT NULL,
+ PRIMARY KEY (`giftcard_id`),
+ UNIQUE KEY `giftcard_number` (`giftcard_number`),
+ KEY `person_id` (`person_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_giftcards`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_inventory`
+--
+
+CREATE TABLE `ospos_inventory` (
+ `trans_id` int(11) NOT NULL AUTO_INCREMENT,
+ `trans_items` int(11) NOT NULL DEFAULT '0',
+ `trans_user` int(11) NOT NULL DEFAULT '0',
+ `trans_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `trans_comment` text NOT NULL,
+ `trans_location` int(11) NOT NULL,
+ `trans_inventory` decimal(15,3) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`trans_id`),
+ KEY `trans_items` (`trans_items`),
+ KEY `trans_user` (`trans_user`),
+ KEY `trans_location` (`trans_location`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
+
+--
+-- Dumping data for table `ospos_inventory`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_items`
+--
+
+CREATE TABLE `ospos_items` (
+ `name` varchar(255) NOT NULL,
+ `category` varchar(255) NOT NULL,
+ `supplier_id` int(11) DEFAULT NULL,
+ `item_number` varchar(255) DEFAULT NULL,
+ `description` varchar(255) NOT NULL,
+ `cost_price` decimal(15,2) NOT NULL,
+ `unit_price` decimal(15,2) NOT NULL,
+ `reorder_level` decimal(15,3) NOT NULL DEFAULT '0',
+ `receiving_quantity` decimal(15,3) NOT NULL DEFAULT '1',
+ `item_id` int(10) NOT NULL AUTO_INCREMENT,
+ `pic_id` int(10) DEFAULT NULL,
+ `allow_alt_description` tinyint(1) NOT NULL,
+ `is_serialized` tinyint(1) NOT NULL,
+ `deleted` int(1) NOT NULL DEFAULT '0',
+ `custom1` VARCHAR(25) NOT NULL,
+ `custom2` VARCHAR(25) NOT NULL,
+ `custom3` VARCHAR(25) NOT NULL,
+ `custom4` VARCHAR(25) NOT NULL,
+ `custom5` VARCHAR(25) NOT NULL,
+ `custom6` VARCHAR(25) NOT NULL,
+ `custom7` VARCHAR(25) NOT NULL,
+ `custom8` VARCHAR(25) NOT NULL,
+ `custom9` VARCHAR(25) NOT NULL,
+ `custom10` VARCHAR(25) NOT NULL,
+ PRIMARY KEY (`item_id`),
+ UNIQUE KEY `item_number` (`item_number`),
+ KEY `supplier_id` (`supplier_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
+
+--
+-- Dumping data for table `ospos_items`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_items_taxes`
+--
+
+CREATE TABLE `ospos_items_taxes` (
+ `item_id` int(10) NOT NULL,
+ `name` varchar(255) NOT NULL,
+ `percent` decimal(15,3) NOT NULL,
+ PRIMARY KEY (`item_id`,`name`,`percent`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_items_taxes`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_item_kits`
+--
+
+CREATE TABLE `ospos_item_kits` (
+ `item_kit_id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` varchar(255) NOT NULL,
+ `description` varchar(255) NOT NULL,
+ PRIMARY KEY (`item_kit_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
+
+--
+-- Dumping data for table `ospos_item_kits`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_item_kit_items`
+--
+
+CREATE TABLE `ospos_item_kit_items` (
+ `item_kit_id` int(11) NOT NULL,
+ `item_id` int(11) NOT NULL,
+ `quantity` decimal(15,3) NOT NULL,
+ PRIMARY KEY (`item_kit_id`,`item_id`,`quantity`),
+ KEY `ospos_item_kit_items_ibfk_2` (`item_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_item_kit_items`
+--
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_item_quantities`
+--
+
+CREATE TABLE IF NOT EXISTS `ospos_item_quantities` (
+ `item_id` int(11) NOT NULL,
+ `location_id` int(11) NOT NULL,
+ `quantity` decimal(15,3) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`item_id`,`location_id`),
+ KEY `item_id` (`item_id`),
+ KEY `location_id` (`location_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_modules`
+--
+
+CREATE TABLE `ospos_modules` (
+ `name_lang_key` varchar(255) NOT NULL,
+ `desc_lang_key` varchar(255) NOT NULL,
+ `sort` int(10) NOT NULL,
+ `module_id` varchar(255) NOT NULL,
+ PRIMARY KEY (`module_id`),
+ UNIQUE KEY `desc_lang_key` (`desc_lang_key`),
+ UNIQUE KEY `name_lang_key` (`name_lang_key`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_modules`
+--
+
+INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_id`) VALUES
+ ('module_config', 'module_config_desc', 110, 'config'),
+ ('module_customers', 'module_customers_desc', 10, 'customers'),
+ ('module_employees', 'module_employees_desc', 80, 'employees'),
+ ('module_giftcards', 'module_giftcards_desc', 90, 'giftcards'),
+ ('module_items', 'module_items_desc', 20, 'items'),
+ ('module_item_kits', 'module_item_kits_desc', 30, 'item_kits'),
+ ('module_messages', 'module_messages_desc', 100, 'messages'),
+ ('module_receivings', 'module_receivings_desc', 60, 'receivings'),
+ ('module_reports', 'module_reports_desc', 50, 'reports'),
+ ('module_sales', 'module_sales_desc', 70, 'sales'),
+ ('module_suppliers', 'module_suppliers_desc', 40, 'suppliers');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_people`
+--
+
+CREATE TABLE `ospos_people` (
+ `first_name` varchar(255) NOT NULL,
+ `last_name` varchar(255) NOT NULL,
+ `gender` int(1) DEFAULT NULL,
+ `phone_number` varchar(255) NOT NULL,
+ `email` varchar(255) NOT NULL,
+ `address_1` varchar(255) NOT NULL,
+ `address_2` varchar(255) NOT NULL,
+ `city` varchar(255) NOT NULL,
+ `state` varchar(255) NOT NULL,
+ `zip` varchar(255) NOT NULL,
+ `country` varchar(255) NOT NULL,
+ `comments` text NOT NULL,
+ `person_id` int(10) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`person_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
+
+--
+-- Dumping data for table `ospos_people`
+--
+
+INSERT INTO `ospos_people` (`first_name`, `last_name`, `phone_number`, `email`, `address_1`, `address_2`, `city`, `state`, `zip`, `country`, `comments`, `person_id`) VALUES
+ ('John', 'Doe', '555-555-5555', 'changeme@example.com', 'Address 1', '', '', '', '', '', '', 1);
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_permissions`
+--
+
+CREATE TABLE `ospos_permissions` (
+ `permission_id` varchar(255) NOT NULL,
+ `module_id` varchar(255) NOT NULL,
+ `location_id` int(10) DEFAULT NULL,
+ PRIMARY KEY (`permission_id`),
+ KEY `module_id` (`module_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_permissions`
+--
+
+INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES
+ ('reports_customers', 'reports'),
+ ('reports_receivings', 'reports'),
+ ('reports_items', 'reports'),
+ ('reports_employees', 'reports'),
+ ('reports_suppliers', 'reports'),
+ ('reports_sales', 'reports'),
+ ('reports_discounts', 'reports'),
+ ('reports_taxes', 'reports'),
+ ('reports_inventory', 'reports'),
+ ('reports_categories', 'reports'),
+ ('reports_payments', 'reports'),
+ ('customers', 'customers'),
+ ('employees', 'employees'),
+ ('giftcards', 'giftcards'),
+ ('items', 'items'),
+ ('item_kits', 'item_kits'),
+ ('messages', 'messages'),
+ ('receivings', 'receivings'),
+ ('reports', 'reports'),
+ ('sales', 'sales'),
+ ('config', 'config'),
+ ('suppliers', 'suppliers');
+
+INSERT INTO `ospos_permissions` (`permission_id`, `module_id`, `location_id`) VALUES
+ ('items_stock', 'items', 1),
+ ('sales_stock', 'sales', 1),
+ ('receivings_stock', 'receivings', 1);
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_grants`
+--
+
+CREATE TABLE `ospos_grants` (
+ `permission_id` varchar(255) NOT NULL,
+ `person_id` int(10) NOT NULL,
+ PRIMARY KEY (`permission_id`,`person_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_grants`
+--
+-- --------------------------------------------------------
+
+INSERT INTO `ospos_grants` (`permission_id`, `person_id`) VALUES
+ ('reports_customers', 1),
+ ('reports_receivings', 1),
+ ('reports_items', 1),
+ ('reports_inventory', 1),
+ ('reports_employees', 1),
+ ('reports_suppliers', 1),
+ ('reports_sales', 1),
+ ('reports_discounts', 1),
+ ('reports_taxes', 1),
+ ('reports_categories', 1),
+ ('reports_payments', 1),
+ ('customers', 1),
+ ('employees', 1),
+ ('giftcards', 1),
+ ('items', 1),
+ ('item_kits', 1),
+ ('messages', 1),
+ ('receivings', 1),
+ ('reports', 1),
+ ('sales', 1),
+ ('config', 1),
+ ('items_stock', 1),
+ ('sales_stock', 1),
+ ('receivings_stock', 1),
+ ('suppliers', 1);
+
+--
+-- Table structure for table `ospos_receivings`
+--
+
+CREATE TABLE `ospos_receivings` (
+ `receiving_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `supplier_id` int(10) DEFAULT NULL,
+ `employee_id` int(10) NOT NULL DEFAULT '0',
+ `comment` text NOT NULL,
+ `receiving_id` int(10) NOT NULL AUTO_INCREMENT,
+ `payment_type` varchar(20) DEFAULT NULL,
+ `reference` varchar(32) DEFAULT NULL,
+ PRIMARY KEY (`receiving_id`),
+ KEY `supplier_id` (`supplier_id`),
+ KEY `employee_id` (`employee_id`),
+ KEY `reference` (`reference`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
+
+--
+-- Dumping data for table `ospos_receivings`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_receivings_items`
+--
+
+CREATE TABLE `ospos_receivings_items` (
+ `receiving_id` int(10) NOT NULL DEFAULT '0',
+ `item_id` int(10) NOT NULL DEFAULT '0',
+ `description` varchar(30) DEFAULT NULL,
+ `serialnumber` varchar(30) DEFAULT NULL,
+ `line` int(3) NOT NULL,
+ `quantity_purchased` decimal(15,3) NOT NULL DEFAULT '0',
+ `item_cost_price` decimal(15,2) NOT NULL,
+ `item_unit_price` decimal(15,2) NOT NULL,
+ `discount_percent` decimal(15,2) NOT NULL DEFAULT '0',
+ `item_location` int(11) NOT NULL,
+ `receiving_quantity` decimal(15,3) NOT NULL DEFAULT '1',
+ PRIMARY KEY (`receiving_id`,`item_id`,`line`),
+ KEY `item_id` (`item_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_receivings_items`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_sales`
+--
+
+CREATE TABLE `ospos_sales` (
+ `sale_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `customer_id` int(10) DEFAULT NULL,
+ `employee_id` int(10) NOT NULL DEFAULT '0',
+ `comment` text NOT NULL,
+ `invoice_number` varchar(32) DEFAULT NULL,
+ `sale_id` int(10) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`sale_id`),
+ KEY `customer_id` (`customer_id`),
+ KEY `employee_id` (`employee_id`),
+ KEY `sale_time` (`sale_time`),
+ UNIQUE KEY `invoice_number` (`invoice_number`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
+
+--
+-- Dumping data for table `ospos_sales`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_sales_items`
+--
+
+CREATE TABLE `ospos_sales_items` (
+ `sale_id` int(10) NOT NULL DEFAULT '0',
+ `item_id` int(10) NOT NULL DEFAULT '0',
+ `description` varchar(30) DEFAULT NULL,
+ `serialnumber` varchar(30) DEFAULT NULL,
+ `line` int(3) NOT NULL DEFAULT '0',
+ `quantity_purchased` decimal(15,3) NOT NULL DEFAULT '0',
+ `item_cost_price` decimal(15,2) NOT NULL,
+ `item_unit_price` decimal(15,2) NOT NULL,
+ `discount_percent` decimal(15,2) NOT NULL DEFAULT '0',
+ `item_location` int(11) NOT NULL,
+ PRIMARY KEY (`sale_id`,`item_id`,`line`),
+ KEY `sale_id` (`sale_id`),
+ KEY `item_id` (`item_id`),
+ KEY `item_location` (`item_location`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_sales_items`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_sales_items_taxes`
+--
+
+CREATE TABLE `ospos_sales_items_taxes` (
+ `sale_id` int(10) NOT NULL,
+ `item_id` int(10) NOT NULL,
+ `line` int(3) NOT NULL DEFAULT '0',
+ `name` varchar(255) NOT NULL,
+ `percent` decimal(15,3) NOT NULL,
+ PRIMARY KEY (`sale_id`,`item_id`,`line`,`name`,`percent`),
+ KEY `sale_id` (`sale_id`),
+ KEY `item_id` (`item_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_sales_items_taxes`
+--
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_sales_payments`
+--
+
+CREATE TABLE `ospos_sales_payments` (
+ `sale_id` int(10) NOT NULL,
+ `payment_type` varchar(40) NOT NULL,
+ `payment_amount` decimal(15,2) NOT NULL,
+ PRIMARY KEY (`sale_id`,`payment_type`),
+ KEY `sale_id` (`sale_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_sales_payments`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_sales_suspended`
+--
+
+CREATE TABLE `ospos_sales_suspended` (
+ `sale_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `customer_id` int(10) DEFAULT NULL,
+ `employee_id` int(10) NOT NULL DEFAULT '0',
+ `comment` text NOT NULL,
+ `invoice_number` varchar(32) DEFAULT NULL,
+ `sale_id` int(10) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`sale_id`),
+ KEY `customer_id` (`customer_id`),
+ KEY `employee_id` (`employee_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
+
+--
+-- Dumping data for table `ospos_sales_suspended`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_sales_suspended_items`
+--
+
+CREATE TABLE `ospos_sales_suspended_items` (
+ `sale_id` int(10) NOT NULL DEFAULT '0',
+ `item_id` int(10) NOT NULL DEFAULT '0',
+ `description` varchar(30) DEFAULT NULL,
+ `serialnumber` varchar(30) DEFAULT NULL,
+ `line` int(3) NOT NULL DEFAULT '0',
+ `quantity_purchased` decimal(15,3) NOT NULL DEFAULT '0',
+ `item_cost_price` decimal(15,2) NOT NULL,
+ `item_unit_price` decimal(15,2) NOT NULL,
+ `discount_percent` decimal(15,2) NOT NULL DEFAULT '0',
+ `item_location` int(11) NOT NULL,
+ PRIMARY KEY (`sale_id`,`item_id`,`line`),
+ KEY `sale_id` (`sale_id`),
+ KEY `item_id` (`item_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_sales_suspended_items`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_sales_suspended_items_taxes`
+--
+
+CREATE TABLE `ospos_sales_suspended_items_taxes` (
+ `sale_id` int(10) NOT NULL,
+ `item_id` int(10) NOT NULL,
+ `line` int(3) NOT NULL DEFAULT '0',
+ `name` varchar(255) NOT NULL,
+ `percent` decimal(15,3) NOT NULL,
+ PRIMARY KEY (`sale_id`,`item_id`,`line`,`name`,`percent`),
+ KEY `item_id` (`item_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_sales_suspended_items_taxes`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_sales_suspended_payments`
+--
+
+CREATE TABLE `ospos_sales_suspended_payments` (
+ `sale_id` int(10) NOT NULL,
+ `payment_type` varchar(40) NOT NULL,
+ `payment_amount` decimal(15,2) NOT NULL,
+ PRIMARY KEY (`sale_id`,`payment_type`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_sales_suspended_payments`
+--
+
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_sessions`
+--
+
+CREATE TABLE `ospos_sessions` (
+ `id` varchar(40) NOT NULL,
+ `ip_address` varchar(45) NOT NULL,
+ `timestamp` int(10) unsigned DEFAULT 0 NOT NULL,
+ `data` blob NOT NULL,
+ KEY `ci_sessions_timestamp` (`timestamp`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_sessions`
+--
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_stock_locations`
+--
+
+CREATE TABLE `ospos_stock_locations` (
+ `location_id` int(11) NOT NULL AUTO_INCREMENT,
+ `location_name` varchar(255) DEFAULT NULL,
+ `deleted` int(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`location_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
+
+--
+-- Dumping data for table `ospos_stock_locations`
+--
+
+INSERT INTO `ospos_stock_locations` ( `deleted`, `location_name` ) VALUES ('0', 'stock');
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `ospos_suppliers`
+--
+
+CREATE TABLE `ospos_suppliers` (
+ `person_id` int(10) NOT NULL,
+ `company_name` varchar(255) NOT NULL,
+ `agency_name` varchar(255) NOT NULL,
+ `account_number` varchar(255) DEFAULT NULL,
+ `deleted` int(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY `person_id` (`person_id`),
+ UNIQUE KEY `account_number` (`account_number`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `ospos_suppliers`
+--
+--
+-- Constraints for dumped tables
+--
+
+--
+-- Constraints for table `ospos_customers`
+--
+ALTER TABLE `ospos_customers`
+ ADD CONSTRAINT `ospos_customers_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
+
+--
+-- Constraints for table `ospos_employees`
+--
+ALTER TABLE `ospos_employees`
+ ADD CONSTRAINT `ospos_employees_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
+
+--
+-- Constraints for table `ospos_inventory`
+--
+ALTER TABLE `ospos_inventory`
+ ADD CONSTRAINT `ospos_inventory_ibfk_1` FOREIGN KEY (`trans_items`) REFERENCES `ospos_items` (`item_id`),
+ ADD CONSTRAINT `ospos_inventory_ibfk_2` FOREIGN KEY (`trans_user`) REFERENCES `ospos_employees` (`person_id`),
+ ADD CONSTRAINT `ospos_inventory_ibfk_3` FOREIGN KEY (`trans_location`) REFERENCES `ospos_stock_locations` (`location_id`);
+
+--
+-- Constraints for table `ospos_items`
+--
+ALTER TABLE `ospos_items`
+ ADD CONSTRAINT `ospos_items_ibfk_1` FOREIGN KEY (`supplier_id`) REFERENCES `ospos_suppliers` (`person_id`);
+
+--
+-- Constraints for table `ospos_items_taxes`
+--
+ALTER TABLE `ospos_items_taxes`
+ ADD CONSTRAINT `ospos_items_taxes_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`) ON DELETE CASCADE;
+
+--
+-- Constraints for table `ospos_item_kit_items`
+--
+ALTER TABLE `ospos_item_kit_items`
+ ADD CONSTRAINT `ospos_item_kit_items_ibfk_1` FOREIGN KEY (`item_kit_id`) REFERENCES `ospos_item_kits` (`item_kit_id`) ON DELETE CASCADE,
+ ADD CONSTRAINT `ospos_item_kit_items_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`) ON DELETE CASCADE;
+
+--
+-- Constraints for table `ospos_permissions`
+--
+ALTER TABLE `ospos_permissions`
+ ADD CONSTRAINT `ospos_permissions_ibfk_1` FOREIGN KEY (`module_id`) REFERENCES `ospos_modules` (`module_id`) ON DELETE CASCADE,
+ ADD CONSTRAINT `ospos_permissions_ibfk_2` FOREIGN KEY (`location_id`) REFERENCES `ospos_stock_locations` (`location_id`) ON DELETE CASCADE;
+
+--
+-- Constraints for table `ospos_grants`
+--
+ALTER TABLE `ospos_grants`
+ ADD CONSTRAINT `ospos_grants_ibfk_1` foreign key (`permission_id`) references `ospos_permissions` (`permission_id`) ON DELETE CASCADE,
+ ADD CONSTRAINT `ospos_grants_ibfk_2` foreign key (`person_id`) references `ospos_employees` (`person_id`) ON DELETE CASCADE;
+
+--
+-- Constraints for table `ospos_receivings`
+--
+ALTER TABLE `ospos_receivings`
+ ADD CONSTRAINT `ospos_receivings_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
+ ADD CONSTRAINT `ospos_receivings_ibfk_2` FOREIGN KEY (`supplier_id`) REFERENCES `ospos_suppliers` (`person_id`);
+
+--
+-- Constraints for table `ospos_receivings_items`
+--
+ALTER TABLE `ospos_receivings_items`
+ ADD CONSTRAINT `ospos_receivings_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
+ ADD CONSTRAINT `ospos_receivings_items_ibfk_2` FOREIGN KEY (`receiving_id`) REFERENCES `ospos_receivings` (`receiving_id`);
+
+--
+-- Constraints for table `ospos_sales`
+--
+ALTER TABLE `ospos_sales`
+ ADD CONSTRAINT `ospos_sales_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
+ ADD CONSTRAINT `ospos_sales_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `ospos_customers` (`person_id`);
+
+--
+-- Constraints for table `ospos_sales_items`
+--
+ALTER TABLE `ospos_sales_items`
+ ADD CONSTRAINT `ospos_sales_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
+ ADD CONSTRAINT `ospos_sales_items_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`),
+ ADD CONSTRAINT `ospos_sales_items_ibfk_3` FOREIGN KEY (`item_location`) REFERENCES `ospos_stock_locations` (`location_id`);
+
+--
+-- Constraints for table `ospos_sales_items_taxes`
+--
+ALTER TABLE `ospos_sales_items_taxes`
+ ADD CONSTRAINT `ospos_sales_items_taxes_ibfk_1` FOREIGN KEY (`sale_id`,`item_id`,`line`) REFERENCES `ospos_sales_items` (`sale_id`,`item_id`,`line`),
+ ADD CONSTRAINT `ospos_sales_items_taxes_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`);
+
+--
+-- Constraints for table `ospos_sales_payments`
+--
+ALTER TABLE `ospos_sales_payments`
+ ADD CONSTRAINT `ospos_sales_payments_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`);
+
+--
+-- Constraints for table `ospos_sales_suspended`
+--
+ALTER TABLE `ospos_sales_suspended`
+ ADD CONSTRAINT `ospos_sales_suspended_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
+ ADD CONSTRAINT `ospos_sales_suspended_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `ospos_customers` (`person_id`);
+
+--
+-- Constraints for table `ospos_sales_suspended_items`
+--
+ALTER TABLE `ospos_sales_suspended_items`
+ ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
+ ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_suspended` (`sale_id`),
+ ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_3` FOREIGN KEY (`item_location`) REFERENCES `ospos_stock_locations` (`location_id`);
+
+--
+-- Constraints for table `ospos_sales_suspended_items_taxes`
+--
+ALTER TABLE `ospos_sales_suspended_items_taxes`
+ ADD CONSTRAINT `ospos_sales_suspended_items_taxes_ibfk_1` FOREIGN KEY (`sale_id`,`item_id`,`line`) REFERENCES `ospos_sales_suspended_items` (`sale_id`,`item_id`,`line`),
+ ADD CONSTRAINT `ospos_sales_suspended_items_taxes_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`);
+
+--
+-- Constraints for table `ospos_sales_suspended_payments`
+--
+ALTER TABLE `ospos_sales_suspended_payments`
+ ADD CONSTRAINT `ospos_sales_suspended_payments_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_suspended` (`sale_id`);
+
+--
+-- Constraints for table `ospos_item_quantities`
+--
+ALTER TABLE `ospos_item_quantities`
+ ADD CONSTRAINT `ospos_item_quantities_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
+ ADD CONSTRAINT `ospos_item_quantities_ibfk_2` FOREIGN KEY (`location_id`) REFERENCES `ospos_stock_locations` (`location_id`);
+
+--
+-- Constraints for table `ospos_suppliers`
+--
+ALTER TABLE `ospos_suppliers`
+ ADD CONSTRAINT `ospos_suppliers_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
+
+--
+-- Constraints for table `ospos_giftcards`
+--
+ALTER TABLE `ospos_giftcards`
+ ADD CONSTRAINT `ospos_giftcards_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml
index 47f7ef996..56d3bb78e 100644
--- a/docker-compose.dev.yml
+++ b/docker-compose.dev.yml
@@ -20,7 +20,6 @@ services:
networks:
- app_net
volumes:
- - ./app/Database/database.sql:/docker-entrypoint-initdb.d/database.sql
- mysql:/var/lib/mysql:rw
environment:
- MYSQL_ROOT_PASSWORD=pointofsale
diff --git a/docker-compose.test.yml b/docker-compose.test.yml
deleted file mode 100644
index 4ff0e18fe..000000000
--- a/docker-compose.test.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-include:
- - docker/docker-mysql.yml
-
-services:
- test:
- build:
- context: .
- target: ospos_test
- depends_on:
- - mysql
- container_name: ospos_test
- environment:
- - CI_ENVIRONMENT=testing
- - ENCRYPTION_KEY=
- - MYSQL_HOST_NAME=mysql
- - MYSQL_DATABASE=ospos
- - MYSQL_USERNAME=admin
- - MYSQL_PASSWORD=pointofsale
- command: [ "/bin/wait-for-it.sh", "mysql:3306", "--", "/app/vendor/bin/phpunit", "/app/tests" ]
- ports:
- - "80:80"
diff --git a/docker-compose.yml b/docker-compose.yml
index 2622a5906..e1ebc9791 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,9 +2,6 @@ include:
- docker/docker-mysql.yml
services:
- sqlscript:
- image: jekkos/opensourcepos:sql-master
- command: /bin/sh -c 'exit 0'
ospos:
image: jekkos/opensourcepos:master
restart: always
diff --git a/docker/docker-mysql.yml b/docker/docker-mysql.yml
index d3e9cf347..69171c645 100644
--- a/docker/docker-mysql.yml
+++ b/docker/docker-mysql.yml
@@ -19,8 +19,6 @@ services:
- "3306"
networks:
- app_net
- volumes_from:
- - sqlscript
volumes:
- mysql:/var/lib/mysql:rw
environment:
diff --git a/gulpfile.js b/gulpfile.js
index e234778dc..909cec7d5 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -259,35 +259,10 @@ gulp.task('copy-fonts', function() {
gulp.task('copy-menubar', function() {
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/star.svg"),rename("attributes.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/bookshelf.svg"),rename("cashups.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/gear.svg"),rename("config.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/contacts.svg"),rename("customers.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/profle.svg"),rename("employees.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/compose.svg"),rename("expenses.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/clipboard.svg"),rename("expenses_categories.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/heart.svg"),rename("giftcards.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/door.svg"),rename("home.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/stack.svg"),rename("item_kits.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/shop.svg"),rename("items.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/smartphone.svg"),rename("messages.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/tools.svg"),rename("migrate.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/door.svg"),rename("office.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/dolly.svg"),rename("receivings.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/bar-chart.svg"),rename("reports.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/cart.svg"),rename("sales.svg"),gulp.dest("public/images/menubar"));
- pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/briefcase.svg"),rename("suppliers.svg"),gulp.dest("public/images/menubar"));
return pipeline(gulp.src('./node_modules/elegant-circles/svg/full-color/money.svg'),rename("taxes.svg"),gulp.dest("public/images/menubar"));
});
-gulp.task('build-database', function() {
- return gulp.src(['./app/Database/tables.sql','./app/Database/constraints.sql'])
- .pipe(header('-- >> This file is autogenerated from tables.sql and constraints.sql. Do not modify directly << --'))
- .pipe(concat('database.sql'))
- .pipe(gulp.dest('./app/Database'));
-});
-
// Run all required tasks
gulp.task('default',
gulp.series('clean',
@@ -299,6 +274,5 @@ gulp.task('default',
'debug-css',
'prod-css',
'copy-fonts',
- 'copy-menubar',
- 'build-database'
+ 'copy-menubar'
));
diff --git a/tests/Libraries/Token_libTest.php b/tests/Libraries/Token_libTest.php
index fac3d92f0..96cd80a41 100644
--- a/tests/Libraries/Token_libTest.php
+++ b/tests/Libraries/Token_libTest.php
@@ -41,7 +41,7 @@ class Token_libTest extends CIUnitTestCase
{
$input = '%Y-%q-%bad';
$result = $this->tokenLib->render($input, [], false);
- $this->assertMatchesRegularExpression('/\d{4}-%q-%bad/', $result);
+ $this->assertMatchesRegularExpression('/\d{4}-%q-[A-Za-z]{3}ad/', $result);
}
public function testRenderHandlesStringWithPercentAPercent(): void
From ba05536317818795207bcab1355432b6b1efe27b Mon Sep 17 00:00:00 2001
From: Ollama
Date: Fri, 20 Mar 2026 19:33:13 +0000
Subject: [PATCH 08/13] refactor: remove tables.sql and constraints.sql (#4447)
These files have been replaced by initial_schema.sql which is now the
authoritative source for the database schema. The initial migration
loads this schema on fresh installs.
- Remove app/Database/tables.sql
- Remove app/Database/constraints.sql
- Schema is frozen in app/Database/Migrations/sqlscripts/initial_schema.sql
---
app/Database/constraints.sql | 145 -------
app/Database/tables.sql | 732 -----------------------------------
2 files changed, 877 deletions(-)
delete mode 100644 app/Database/constraints.sql
delete mode 100644 app/Database/tables.sql
diff --git a/app/Database/constraints.sql b/app/Database/constraints.sql
deleted file mode 100644
index 84c9ea292..000000000
--- a/app/Database/constraints.sql
+++ /dev/null
@@ -1,145 +0,0 @@
---
--- Constraints for dumped tables
---
-
---
--- Constraints for table `ospos_customers`
---
-ALTER TABLE `ospos_customers`
- ADD CONSTRAINT `ospos_customers_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
-
---
--- Constraints for table `ospos_employees`
---
-ALTER TABLE `ospos_employees`
- ADD CONSTRAINT `ospos_employees_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
-
---
--- Constraints for table `ospos_inventory`
---
-ALTER TABLE `ospos_inventory`
- ADD CONSTRAINT `ospos_inventory_ibfk_1` FOREIGN KEY (`trans_items`) REFERENCES `ospos_items` (`item_id`),
- ADD CONSTRAINT `ospos_inventory_ibfk_2` FOREIGN KEY (`trans_user`) REFERENCES `ospos_employees` (`person_id`),
- ADD CONSTRAINT `ospos_inventory_ibfk_3` FOREIGN KEY (`trans_location`) REFERENCES `ospos_stock_locations` (`location_id`);
-
---
--- Constraints for table `ospos_items`
---
-ALTER TABLE `ospos_items`
- ADD CONSTRAINT `ospos_items_ibfk_1` FOREIGN KEY (`supplier_id`) REFERENCES `ospos_suppliers` (`person_id`);
-
---
--- Constraints for table `ospos_items_taxes`
---
-ALTER TABLE `ospos_items_taxes`
- ADD CONSTRAINT `ospos_items_taxes_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`) ON DELETE CASCADE;
-
---
--- Constraints for table `ospos_item_kit_items`
---
-ALTER TABLE `ospos_item_kit_items`
- ADD CONSTRAINT `ospos_item_kit_items_ibfk_1` FOREIGN KEY (`item_kit_id`) REFERENCES `ospos_item_kits` (`item_kit_id`) ON DELETE CASCADE,
- ADD CONSTRAINT `ospos_item_kit_items_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`) ON DELETE CASCADE;
-
---
--- Constraints for table `ospos_permissions`
---
-ALTER TABLE `ospos_permissions`
- ADD CONSTRAINT `ospos_permissions_ibfk_1` FOREIGN KEY (`module_id`) REFERENCES `ospos_modules` (`module_id`) ON DELETE CASCADE,
- ADD CONSTRAINT `ospos_permissions_ibfk_2` FOREIGN KEY (`location_id`) REFERENCES `ospos_stock_locations` (`location_id`) ON DELETE CASCADE;
-
---
--- Constraints for table `ospos_grants`
---
-ALTER TABLE `ospos_grants`
- ADD CONSTRAINT `ospos_grants_ibfk_1` foreign key (`permission_id`) references `ospos_permissions` (`permission_id`) ON DELETE CASCADE,
- ADD CONSTRAINT `ospos_grants_ibfk_2` foreign key (`person_id`) references `ospos_employees` (`person_id`) ON DELETE CASCADE;
-
---
--- Constraints for table `ospos_receivings`
---
-ALTER TABLE `ospos_receivings`
- ADD CONSTRAINT `ospos_receivings_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
- ADD CONSTRAINT `ospos_receivings_ibfk_2` FOREIGN KEY (`supplier_id`) REFERENCES `ospos_suppliers` (`person_id`);
-
---
--- Constraints for table `ospos_receivings_items`
---
-ALTER TABLE `ospos_receivings_items`
- ADD CONSTRAINT `ospos_receivings_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
- ADD CONSTRAINT `ospos_receivings_items_ibfk_2` FOREIGN KEY (`receiving_id`) REFERENCES `ospos_receivings` (`receiving_id`);
-
---
--- Constraints for table `ospos_sales`
---
-ALTER TABLE `ospos_sales`
- ADD CONSTRAINT `ospos_sales_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
- ADD CONSTRAINT `ospos_sales_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `ospos_customers` (`person_id`);
-
---
--- Constraints for table `ospos_sales_items`
---
-ALTER TABLE `ospos_sales_items`
- ADD CONSTRAINT `ospos_sales_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
- ADD CONSTRAINT `ospos_sales_items_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`),
- ADD CONSTRAINT `ospos_sales_items_ibfk_3` FOREIGN KEY (`item_location`) REFERENCES `ospos_stock_locations` (`location_id`);
-
---
--- Constraints for table `ospos_sales_items_taxes`
---
-ALTER TABLE `ospos_sales_items_taxes`
- ADD CONSTRAINT `ospos_sales_items_taxes_ibfk_1` FOREIGN KEY (`sale_id`,`item_id`,`line`) REFERENCES `ospos_sales_items` (`sale_id`,`item_id`,`line`),
- ADD CONSTRAINT `ospos_sales_items_taxes_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`);
-
---
--- Constraints for table `ospos_sales_payments`
---
-ALTER TABLE `ospos_sales_payments`
- ADD CONSTRAINT `ospos_sales_payments_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales` (`sale_id`);
-
---
--- Constraints for table `ospos_sales_suspended`
---
-ALTER TABLE `ospos_sales_suspended`
- ADD CONSTRAINT `ospos_sales_suspended_ibfk_1` FOREIGN KEY (`employee_id`) REFERENCES `ospos_employees` (`person_id`),
- ADD CONSTRAINT `ospos_sales_suspended_ibfk_2` FOREIGN KEY (`customer_id`) REFERENCES `ospos_customers` (`person_id`);
-
---
--- Constraints for table `ospos_sales_suspended_items`
---
-ALTER TABLE `ospos_sales_suspended_items`
- ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
- ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_2` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_suspended` (`sale_id`),
- ADD CONSTRAINT `ospos_sales_suspended_items_ibfk_3` FOREIGN KEY (`item_location`) REFERENCES `ospos_stock_locations` (`location_id`);
-
---
--- Constraints for table `ospos_sales_suspended_items_taxes`
---
-ALTER TABLE `ospos_sales_suspended_items_taxes`
- ADD CONSTRAINT `ospos_sales_suspended_items_taxes_ibfk_1` FOREIGN KEY (`sale_id`,`item_id`,`line`) REFERENCES `ospos_sales_suspended_items` (`sale_id`,`item_id`,`line`),
- ADD CONSTRAINT `ospos_sales_suspended_items_taxes_ibfk_2` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`);
-
---
--- Constraints for table `ospos_sales_suspended_payments`
---
-ALTER TABLE `ospos_sales_suspended_payments`
- ADD CONSTRAINT `ospos_sales_suspended_payments_ibfk_1` FOREIGN KEY (`sale_id`) REFERENCES `ospos_sales_suspended` (`sale_id`);
-
---
--- Constraints for table `ospos_item_quantities`
---
-ALTER TABLE `ospos_item_quantities`
- ADD CONSTRAINT `ospos_item_quantities_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `ospos_items` (`item_id`),
- ADD CONSTRAINT `ospos_item_quantities_ibfk_2` FOREIGN KEY (`location_id`) REFERENCES `ospos_stock_locations` (`location_id`);
-
---
--- Constraints for table `ospos_suppliers`
---
-ALTER TABLE `ospos_suppliers`
- ADD CONSTRAINT `ospos_suppliers_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
-
---
--- Constraints for table `ospos_giftcards`
---
-ALTER TABLE `ospos_giftcards`
- ADD CONSTRAINT `ospos_giftcards_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`);
diff --git a/app/Database/tables.sql b/app/Database/tables.sql
deleted file mode 100644
index 943706722..000000000
--- a/app/Database/tables.sql
+++ /dev/null
@@ -1,732 +0,0 @@
-
---
--- Table structure for table `ospos_app_config`
---
-
-CREATE TABLE `ospos_app_config` (
- `key` varchar(50) NOT NULL,
- `value` varchar(500) NOT NULL,
- PRIMARY KEY (`key`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_app_config`
---
-
-INSERT INTO `ospos_app_config` (`key`, `value`) VALUES
- ('address', '123 Nowhere street'),
- ('company', 'Open Source Point of Sale'),
- ('default_tax_rate', '8'),
- ('email', 'changeme@example.com'),
- ('fax', ''),
- ('phone', '555-555-5555'),
- ('return_policy', 'Test'),
- ('timezone', 'America/New_York'),
- ('website', ''),
- ('company_logo', ''),
- ('tax_included', '0'),
- ('barcode_content', 'id'),
- ('barcode_type', 'Code39'),
- ('barcode_width', '250'),
- ('barcode_height', '50'),
- ('barcode_quality', '100'),
- ('barcode_font', 'Arial'),
- ('barcode_font_size', '10'),
- ('barcode_first_row', 'category'),
- ('barcode_second_row', 'item_code'),
- ('barcode_third_row', 'unit_price'),
- ('barcode_num_in_row', '2'),
- ('barcode_page_width', '100'),
- ('barcode_page_cellspacing', '20'),
- ('barcode_generate_if_empty', '0'),
- ('receipt_show_taxes', '0'),
- ('receipt_show_total_discount', '1'),
- ('receipt_show_description', '1'),
- ('receipt_show_serialnumber', '1'),
- ('invoice_enable', '1'),
- ('recv_invoice_format', '$CO'),
- ('sales_invoice_format', '$CO'),
- ('invoice_email_message', 'Dear $CU, In attachment the receipt for sale $INV'),
- ('invoice_default_comments', 'This is a default comment'),
- ('print_silently', '1'),
- ('print_header', '0'),
- ('print_footer', '0'),
- ('print_top_margin', '0'),
- ('print_left_margin', '0'),
- ('print_bottom_margin', '0'),
- ('print_right_margin', '0'),
- ('default_sales_discount', '0'),
- ('lines_per_page', '25'),
- ('dateformat', 'm/d/Y'),
- ('timeformat', 'H:i:s'),
- ('currency_symbol', '$'),
- ('number_locale', 'en_US'),
- ('thousands_separator', '1'),
- ('currency_decimals', '2'),
- ('tax_decimals', '2'),
- ('quantity_decimals', '0'),
- ('country_codes', 'us'),
- ('msg_msg', ''),
- ('msg_uid', ''),
- ('msg_src', ''),
- ('msg_pwd', ''),
- ('notify_horizontal_position', 'center'),
- ('notify_vertical_position', 'bottom'),
- ('payment_options_order', 'cashdebitcredit'),
- ('protocol', 'mail'),
- ('mailpath', '/usr/sbin/sendmail'),
- ('smtp_port', '465'),
- ('smtp_timeout', '5'),
- ('smtp_crypto', 'ssl'),
- ('receipt_template', 'receipt_default'),
- ('theme', 'flatly'),
- ('statistics', '1'),
- ('language', 'english'),
- ('language_code', 'en');
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_customers`
---
-
-CREATE TABLE `ospos_customers` (
- `person_id` int(10) NOT NULL,
- `company_name` varchar(255) DEFAULT NULL,
- `account_number` varchar(255) DEFAULT NULL,
- `taxable` int(1) NOT NULL DEFAULT '1',
- `discount_percent` decimal(15,2) NOT NULL DEFAULT '0',
- `deleted` int(1) NOT NULL DEFAULT '0',
- PRIMARY KEY `person_id` (`person_id`),
- UNIQUE KEY `account_number` (`account_number`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_customers`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_employees`
---
-
-CREATE TABLE `ospos_employees` (
- `username` varchar(255) NOT NULL,
- `password` varchar(255) NOT NULL,
- `person_id` int(10) NOT NULL,
- `deleted` int(1) NOT NULL DEFAULT '0',
- `hash_version` int(1) NOT NULL DEFAULT '2',
- PRIMARY KEY `person_id` (`person_id`),
- UNIQUE KEY `username` (`username`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_employees`
---
-
-INSERT INTO `ospos_employees` (`username`, `password`, `person_id`, `deleted`, `hash_version`) VALUES
- ('admin', '$2y$10$vJBSMlD02EC7ENSrKfVQXuvq9tNRHMtcOA8MSK2NYS748HHWm.gcG', 1, 0, 2);
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_giftcards`
---
-
-CREATE TABLE `ospos_giftcards` (
- `record_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `giftcard_id` int(11) NOT NULL AUTO_INCREMENT,
- `giftcard_number` int(10) NOT NULL,
- `value` decimal(15,2) NOT NULL,
- `deleted` int(1) NOT NULL DEFAULT '0',
- `person_id` INT(10) DEFAULT NULL,
- PRIMARY KEY (`giftcard_id`),
- UNIQUE KEY `giftcard_number` (`giftcard_number`),
- KEY `person_id` (`person_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_giftcards`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_inventory`
---
-
-CREATE TABLE `ospos_inventory` (
- `trans_id` int(11) NOT NULL AUTO_INCREMENT,
- `trans_items` int(11) NOT NULL DEFAULT '0',
- `trans_user` int(11) NOT NULL DEFAULT '0',
- `trans_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `trans_comment` text NOT NULL,
- `trans_location` int(11) NOT NULL,
- `trans_inventory` decimal(15,3) NOT NULL DEFAULT '0',
- PRIMARY KEY (`trans_id`),
- KEY `trans_items` (`trans_items`),
- KEY `trans_user` (`trans_user`),
- KEY `trans_location` (`trans_location`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
-
---
--- Dumping data for table `ospos_inventory`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_items`
---
-
-CREATE TABLE `ospos_items` (
- `name` varchar(255) NOT NULL,
- `category` varchar(255) NOT NULL,
- `supplier_id` int(11) DEFAULT NULL,
- `item_number` varchar(255) DEFAULT NULL,
- `description` varchar(255) NOT NULL,
- `cost_price` decimal(15,2) NOT NULL,
- `unit_price` decimal(15,2) NOT NULL,
- `reorder_level` decimal(15,3) NOT NULL DEFAULT '0',
- `receiving_quantity` decimal(15,3) NOT NULL DEFAULT '1',
- `item_id` int(10) NOT NULL AUTO_INCREMENT,
- `pic_id` int(10) DEFAULT NULL,
- `allow_alt_description` tinyint(1) NOT NULL,
- `is_serialized` tinyint(1) NOT NULL,
- `deleted` int(1) NOT NULL DEFAULT '0',
- `custom1` VARCHAR(25) NOT NULL,
- `custom2` VARCHAR(25) NOT NULL,
- `custom3` VARCHAR(25) NOT NULL,
- `custom4` VARCHAR(25) NOT NULL,
- `custom5` VARCHAR(25) NOT NULL,
- `custom6` VARCHAR(25) NOT NULL,
- `custom7` VARCHAR(25) NOT NULL,
- `custom8` VARCHAR(25) NOT NULL,
- `custom9` VARCHAR(25) NOT NULL,
- `custom10` VARCHAR(25) NOT NULL,
- PRIMARY KEY (`item_id`),
- UNIQUE KEY `item_number` (`item_number`),
- KEY `supplier_id` (`supplier_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
-
---
--- Dumping data for table `ospos_items`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_items_taxes`
---
-
-CREATE TABLE `ospos_items_taxes` (
- `item_id` int(10) NOT NULL,
- `name` varchar(255) NOT NULL,
- `percent` decimal(15,3) NOT NULL,
- PRIMARY KEY (`item_id`,`name`,`percent`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_items_taxes`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_item_kits`
---
-
-CREATE TABLE `ospos_item_kits` (
- `item_kit_id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(255) NOT NULL,
- `description` varchar(255) NOT NULL,
- PRIMARY KEY (`item_kit_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
-
---
--- Dumping data for table `ospos_item_kits`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_item_kit_items`
---
-
-CREATE TABLE `ospos_item_kit_items` (
- `item_kit_id` int(11) NOT NULL,
- `item_id` int(11) NOT NULL,
- `quantity` decimal(15,3) NOT NULL,
- PRIMARY KEY (`item_kit_id`,`item_id`,`quantity`),
- KEY `ospos_item_kit_items_ibfk_2` (`item_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_item_kit_items`
---
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_item_quantities`
---
-
-CREATE TABLE IF NOT EXISTS `ospos_item_quantities` (
- `item_id` int(11) NOT NULL,
- `location_id` int(11) NOT NULL,
- `quantity` decimal(15,3) NOT NULL DEFAULT '0',
- PRIMARY KEY (`item_id`,`location_id`),
- KEY `item_id` (`item_id`),
- KEY `location_id` (`location_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_modules`
---
-
-CREATE TABLE `ospos_modules` (
- `name_lang_key` varchar(255) NOT NULL,
- `desc_lang_key` varchar(255) NOT NULL,
- `sort` int(10) NOT NULL,
- `module_id` varchar(255) NOT NULL,
- PRIMARY KEY (`module_id`),
- UNIQUE KEY `desc_lang_key` (`desc_lang_key`),
- UNIQUE KEY `name_lang_key` (`name_lang_key`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_modules`
---
-
-INSERT INTO `ospos_modules` (`name_lang_key`, `desc_lang_key`, `sort`, `module_id`) VALUES
- ('module_config', 'module_config_desc', 110, 'config'),
- ('module_customers', 'module_customers_desc', 10, 'customers'),
- ('module_employees', 'module_employees_desc', 80, 'employees'),
- ('module_giftcards', 'module_giftcards_desc', 90, 'giftcards'),
- ('module_items', 'module_items_desc', 20, 'items'),
- ('module_item_kits', 'module_item_kits_desc', 30, 'item_kits'),
- ('module_messages', 'module_messages_desc', 100, 'messages'),
- ('module_receivings', 'module_receivings_desc', 60, 'receivings'),
- ('module_reports', 'module_reports_desc', 50, 'reports'),
- ('module_sales', 'module_sales_desc', 70, 'sales'),
- ('module_suppliers', 'module_suppliers_desc', 40, 'suppliers');
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_people`
---
-
-CREATE TABLE `ospos_people` (
- `first_name` varchar(255) NOT NULL,
- `last_name` varchar(255) NOT NULL,
- `gender` int(1) DEFAULT NULL,
- `phone_number` varchar(255) NOT NULL,
- `email` varchar(255) NOT NULL,
- `address_1` varchar(255) NOT NULL,
- `address_2` varchar(255) NOT NULL,
- `city` varchar(255) NOT NULL,
- `state` varchar(255) NOT NULL,
- `zip` varchar(255) NOT NULL,
- `country` varchar(255) NOT NULL,
- `comments` text NOT NULL,
- `person_id` int(10) NOT NULL AUTO_INCREMENT,
- PRIMARY KEY (`person_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
-
---
--- Dumping data for table `ospos_people`
---
-
-INSERT INTO `ospos_people` (`first_name`, `last_name`, `phone_number`, `email`, `address_1`, `address_2`, `city`, `state`, `zip`, `country`, `comments`, `person_id`) VALUES
- ('John', 'Doe', '555-555-5555', 'changeme@example.com', 'Address 1', '', '', '', '', '', '', 1);
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_permissions`
---
-
-CREATE TABLE `ospos_permissions` (
- `permission_id` varchar(255) NOT NULL,
- `module_id` varchar(255) NOT NULL,
- `location_id` int(10) DEFAULT NULL,
- PRIMARY KEY (`permission_id`),
- KEY `module_id` (`module_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_permissions`
---
-
-INSERT INTO `ospos_permissions` (`permission_id`, `module_id`) VALUES
- ('reports_customers', 'reports'),
- ('reports_receivings', 'reports'),
- ('reports_items', 'reports'),
- ('reports_employees', 'reports'),
- ('reports_suppliers', 'reports'),
- ('reports_sales', 'reports'),
- ('reports_discounts', 'reports'),
- ('reports_taxes', 'reports'),
- ('reports_inventory', 'reports'),
- ('reports_categories', 'reports'),
- ('reports_payments', 'reports'),
- ('customers', 'customers'),
- ('employees', 'employees'),
- ('giftcards', 'giftcards'),
- ('items', 'items'),
- ('item_kits', 'item_kits'),
- ('messages', 'messages'),
- ('receivings', 'receivings'),
- ('reports', 'reports'),
- ('sales', 'sales'),
- ('config', 'config'),
- ('suppliers', 'suppliers');
-
-INSERT INTO `ospos_permissions` (`permission_id`, `module_id`, `location_id`) VALUES
- ('items_stock', 'items', 1),
- ('sales_stock', 'sales', 1),
- ('receivings_stock', 'receivings', 1);
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_grants`
---
-
-CREATE TABLE `ospos_grants` (
- `permission_id` varchar(255) NOT NULL,
- `person_id` int(10) NOT NULL,
- PRIMARY KEY (`permission_id`,`person_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_grants`
---
--- --------------------------------------------------------
-
-INSERT INTO `ospos_grants` (`permission_id`, `person_id`) VALUES
- ('reports_customers', 1),
- ('reports_receivings', 1),
- ('reports_items', 1),
- ('reports_inventory', 1),
- ('reports_employees', 1),
- ('reports_suppliers', 1),
- ('reports_sales', 1),
- ('reports_discounts', 1),
- ('reports_taxes', 1),
- ('reports_categories', 1),
- ('reports_payments', 1),
- ('customers', 1),
- ('employees', 1),
- ('giftcards', 1),
- ('items', 1),
- ('item_kits', 1),
- ('messages', 1),
- ('receivings', 1),
- ('reports', 1),
- ('sales', 1),
- ('config', 1),
- ('items_stock', 1),
- ('sales_stock', 1),
- ('receivings_stock', 1),
- ('suppliers', 1);
-
---
--- Table structure for table `ospos_receivings`
---
-
-CREATE TABLE `ospos_receivings` (
- `receiving_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `supplier_id` int(10) DEFAULT NULL,
- `employee_id` int(10) NOT NULL DEFAULT '0',
- `comment` text NOT NULL,
- `receiving_id` int(10) NOT NULL AUTO_INCREMENT,
- `payment_type` varchar(20) DEFAULT NULL,
- `reference` varchar(32) DEFAULT NULL,
- PRIMARY KEY (`receiving_id`),
- KEY `supplier_id` (`supplier_id`),
- KEY `employee_id` (`employee_id`),
- KEY `reference` (`reference`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
-
---
--- Dumping data for table `ospos_receivings`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_receivings_items`
---
-
-CREATE TABLE `ospos_receivings_items` (
- `receiving_id` int(10) NOT NULL DEFAULT '0',
- `item_id` int(10) NOT NULL DEFAULT '0',
- `description` varchar(30) DEFAULT NULL,
- `serialnumber` varchar(30) DEFAULT NULL,
- `line` int(3) NOT NULL,
- `quantity_purchased` decimal(15,3) NOT NULL DEFAULT '0',
- `item_cost_price` decimal(15,2) NOT NULL,
- `item_unit_price` decimal(15,2) NOT NULL,
- `discount_percent` decimal(15,2) NOT NULL DEFAULT '0',
- `item_location` int(11) NOT NULL,
- `receiving_quantity` decimal(15,3) NOT NULL DEFAULT '1',
- PRIMARY KEY (`receiving_id`,`item_id`,`line`),
- KEY `item_id` (`item_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_receivings_items`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_sales`
---
-
-CREATE TABLE `ospos_sales` (
- `sale_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `customer_id` int(10) DEFAULT NULL,
- `employee_id` int(10) NOT NULL DEFAULT '0',
- `comment` text NOT NULL,
- `invoice_number` varchar(32) DEFAULT NULL,
- `sale_id` int(10) NOT NULL AUTO_INCREMENT,
- PRIMARY KEY (`sale_id`),
- KEY `customer_id` (`customer_id`),
- KEY `employee_id` (`employee_id`),
- KEY `sale_time` (`sale_time`),
- UNIQUE KEY `invoice_number` (`invoice_number`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
-
---
--- Dumping data for table `ospos_sales`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_sales_items`
---
-
-CREATE TABLE `ospos_sales_items` (
- `sale_id` int(10) NOT NULL DEFAULT '0',
- `item_id` int(10) NOT NULL DEFAULT '0',
- `description` varchar(30) DEFAULT NULL,
- `serialnumber` varchar(30) DEFAULT NULL,
- `line` int(3) NOT NULL DEFAULT '0',
- `quantity_purchased` decimal(15,3) NOT NULL DEFAULT '0',
- `item_cost_price` decimal(15,2) NOT NULL,
- `item_unit_price` decimal(15,2) NOT NULL,
- `discount_percent` decimal(15,2) NOT NULL DEFAULT '0',
- `item_location` int(11) NOT NULL,
- PRIMARY KEY (`sale_id`,`item_id`,`line`),
- KEY `sale_id` (`sale_id`),
- KEY `item_id` (`item_id`),
- KEY `item_location` (`item_location`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_sales_items`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_sales_items_taxes`
---
-
-CREATE TABLE `ospos_sales_items_taxes` (
- `sale_id` int(10) NOT NULL,
- `item_id` int(10) NOT NULL,
- `line` int(3) NOT NULL DEFAULT '0',
- `name` varchar(255) NOT NULL,
- `percent` decimal(15,3) NOT NULL,
- PRIMARY KEY (`sale_id`,`item_id`,`line`,`name`,`percent`),
- KEY `sale_id` (`sale_id`),
- KEY `item_id` (`item_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_sales_items_taxes`
---
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_sales_payments`
---
-
-CREATE TABLE `ospos_sales_payments` (
- `sale_id` int(10) NOT NULL,
- `payment_type` varchar(40) NOT NULL,
- `payment_amount` decimal(15,2) NOT NULL,
- PRIMARY KEY (`sale_id`,`payment_type`),
- KEY `sale_id` (`sale_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_sales_payments`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_sales_suspended`
---
-
-CREATE TABLE `ospos_sales_suspended` (
- `sale_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `customer_id` int(10) DEFAULT NULL,
- `employee_id` int(10) NOT NULL DEFAULT '0',
- `comment` text NOT NULL,
- `invoice_number` varchar(32) DEFAULT NULL,
- `sale_id` int(10) NOT NULL AUTO_INCREMENT,
- PRIMARY KEY (`sale_id`),
- KEY `customer_id` (`customer_id`),
- KEY `employee_id` (`employee_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
-
---
--- Dumping data for table `ospos_sales_suspended`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_sales_suspended_items`
---
-
-CREATE TABLE `ospos_sales_suspended_items` (
- `sale_id` int(10) NOT NULL DEFAULT '0',
- `item_id` int(10) NOT NULL DEFAULT '0',
- `description` varchar(30) DEFAULT NULL,
- `serialnumber` varchar(30) DEFAULT NULL,
- `line` int(3) NOT NULL DEFAULT '0',
- `quantity_purchased` decimal(15,3) NOT NULL DEFAULT '0',
- `item_cost_price` decimal(15,2) NOT NULL,
- `item_unit_price` decimal(15,2) NOT NULL,
- `discount_percent` decimal(15,2) NOT NULL DEFAULT '0',
- `item_location` int(11) NOT NULL,
- PRIMARY KEY (`sale_id`,`item_id`,`line`),
- KEY `sale_id` (`sale_id`),
- KEY `item_id` (`item_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_sales_suspended_items`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_sales_suspended_items_taxes`
---
-
-CREATE TABLE `ospos_sales_suspended_items_taxes` (
- `sale_id` int(10) NOT NULL,
- `item_id` int(10) NOT NULL,
- `line` int(3) NOT NULL DEFAULT '0',
- `name` varchar(255) NOT NULL,
- `percent` decimal(15,3) NOT NULL,
- PRIMARY KEY (`sale_id`,`item_id`,`line`,`name`,`percent`),
- KEY `item_id` (`item_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_sales_suspended_items_taxes`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_sales_suspended_payments`
---
-
-CREATE TABLE `ospos_sales_suspended_payments` (
- `sale_id` int(10) NOT NULL,
- `payment_type` varchar(40) NOT NULL,
- `payment_amount` decimal(15,2) NOT NULL,
- PRIMARY KEY (`sale_id`,`payment_type`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_sales_suspended_payments`
---
-
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_sessions`
---
-
-CREATE TABLE `ospos_sessions` (
- `id` varchar(40) NOT NULL,
- `ip_address` varchar(45) NOT NULL,
- `timestamp` int(10) unsigned DEFAULT 0 NOT NULL,
- `data` blob NOT NULL,
- KEY `ci_sessions_timestamp` (`timestamp`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_sessions`
---
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_stock_locations`
---
-
-CREATE TABLE `ospos_stock_locations` (
- `location_id` int(11) NOT NULL AUTO_INCREMENT,
- `location_name` varchar(255) DEFAULT NULL,
- `deleted` int(1) NOT NULL DEFAULT '0',
- PRIMARY KEY (`location_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
-
---
--- Dumping data for table `ospos_stock_locations`
---
-
-INSERT INTO `ospos_stock_locations` ( `deleted`, `location_name` ) VALUES ('0', 'stock');
-
--- --------------------------------------------------------
-
---
--- Table structure for table `ospos_suppliers`
---
-
-CREATE TABLE `ospos_suppliers` (
- `person_id` int(10) NOT NULL,
- `company_name` varchar(255) NOT NULL,
- `agency_name` varchar(255) NOT NULL,
- `account_number` varchar(255) DEFAULT NULL,
- `deleted` int(1) NOT NULL DEFAULT '0',
- PRIMARY KEY `person_id` (`person_id`),
- UNIQUE KEY `account_number` (`account_number`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `ospos_suppliers`
---
From 68e9a5663238ac65bd9354bf75792c4f94d936ee Mon Sep 17 00:00:00 2001
From: Ollama
Date: Fri, 20 Mar 2026 19:36:11 +0000
Subject: [PATCH 09/13] refactor: remove build-database gulp task (#4447)
The build-database task previously concatenated tables.sql and constraints.sql
into database.sql. Since we now use initial_schema.sql directly in migrations,
this task is no longer needed.
- Remove gulp task 'build-database'
- Keep all other build tasks intact
---
gulpfile.js | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/gulpfile.js b/gulpfile.js
index 909cec7d5..38388de33 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -259,6 +259,24 @@ gulp.task('copy-fonts', function() {
gulp.task('copy-menubar', function() {
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/star.svg"),rename("attributes.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/bookshelf.svg"),rename("cashups.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/gear.svg"),rename("config.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/contacts.svg"),rename("customers.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/profle.svg"),rename("employees.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/compose.svg"),rename("expenses.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/clipboard.svg"),rename("expenses_categories.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/heart.svg"),rename("giftcards.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/door.svg"),rename("home.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/stack.svg"),rename("item_kits.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/shop.svg"),rename("items.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/smartphone.svg"),rename("messages.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/tools.svg"),rename("migrate.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/door.svg"),rename("office.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/dolly.svg"),rename("receivings.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/bar-chart.svg"),rename("reports.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/cart.svg"),rename("sales.svg"),gulp.dest("public/images/menubar"));
+ pipeline(gulp.src("./node_modules/elegant-circles/svg/full-color/briefcase.svg"),rename("suppliers.svg"),gulp.dest("public/images/menubar"));
return pipeline(gulp.src('./node_modules/elegant-circles/svg/full-color/money.svg'),rename("taxes.svg"),gulp.dest("public/images/menubar"));
});
From cef103445ef5e2a2b23a5eeed78dd2ee71b05a43 Mon Sep 17 00:00:00 2001
From: Ollama
Date: Tue, 24 Mar 2026 08:00:56 +0000
Subject: [PATCH 10/13] refactor: optimize Docker image size
- Combine RUN commands to reduce layers
- Add --no-install-recommends and clean apt cache
- Use COPY --chown to set ownership during copy
- Update .dockerignore to exclude dev files and build configs
Saves ~260MB (21%) in image size
---
.dockerignore | 55 ++++++++++++++++++++++++++++++++++++++++-----------
Dockerfile | 19 ++++++++++++------
2 files changed, 57 insertions(+), 17 deletions(-)
diff --git a/.dockerignore b/.dockerignore
index 42dc9d58b..e0c9a46d6 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,23 +1,56 @@
-node_modules
-tmp
+# Version control
+.git
+.gitignore
+
+# Sensitive config (user may mount their own)
app/Config/Email.php
+
+# Build artifacts
+node_modules/
+dist/
+tmp/
*.patch
patches/
+
+# IDE and editor files
.idea/
-git-svn-diff.py
-*.bash
+.vscode/
.swp
+*.swp
.buildpath
.project
-.settings/*
-.git
-dist/
-node_modules/
-*.swp
+.settings/
+
+# Development tools and configs
+tests/
+phpunit.xml
+.php-cs-fixer.*
+phpstan.neon
+*.bash
+git-svn-diff.py
+
+# Documentation
+*.md
+!LICENSE
+branding/
+
+# Build configs (not needed at runtime)
+composer.json
+composer.lock
+package.json
+package-lock.json
+gulpfile.js
+.env.example
+.dockerignore
+
+# Temporary and backup files
*.rej
*.orig
*~
*.~
*.log
-app/writable/session/*
-!app/writable/session/index.html
+
+# CI
+.github/
+.github/workflows/
+build/
diff --git a/Dockerfile b/Dockerfile
index ca1b5a46c..db1f8a1c1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,15 +1,22 @@
FROM php:8.2-apache AS ospos
LABEL maintainer="jekkos"
-RUN apt update && apt-get install -y libicu-dev libgd-dev
-RUN a2enmod rewrite
-RUN docker-php-ext-install mysqli bcmath intl gd
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ libicu-dev \
+ libgd-dev \
+ && docker-php-ext-install mysqli bcmath intl gd \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/* \
+ && a2enmod rewrite
+
RUN echo "date.timezone = \"\${PHP_TIMEZONE}\"" > /usr/local/etc/php/conf.d/timezone.ini
WORKDIR /app
-COPY . /app
-RUN ln -s /app/*[^public] /var/www && rm -rf /var/www/html && ln -nsf /app/public /var/www/html
-RUN chmod -R 770 /app/writable/uploads /app/writable/logs /app/writable/cache && chown -R www-data:www-data /app
+COPY --chown=www-data:www-data . /app
+RUN chmod 770 /app/writable/uploads /app/writable/logs /app/writable/cache \
+ && ln -s /app/*[^public] /var/www \
+ && rm -rf /var/www/html \
+ && ln -nsf /app/public /var/www/html
FROM ospos AS ospos_dev
From 56670271d68b81c53e048fc5f98910e66d3bc4d8 Mon Sep 17 00:00:00 2001
From: Ollama
Date: Fri, 27 Mar 2026 07:54:37 +0000
Subject: [PATCH 11/13] fix: remove duplicate phpunit.xml that prevented tests
from running
The tests/phpunit.xml was incomplete - it only configured helpers and
Libraries testsuites, while phpunit.xml.dist at root contains all tests.
PHPUnit was likely using the incomplete config, resulting in empty test
results.
---
tests/phpunit.xml | 18 ------------------
1 file changed, 18 deletions(-)
delete mode 100644 tests/phpunit.xml
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
deleted file mode 100644
index fefec4218..000000000
--- a/tests/phpunit.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
- helpers
-
-
- Libraries
-
-
-
-
From 9d5019e12ee6e09f18f8eb359c02d01369434689 Mon Sep 17 00:00:00 2001
From: Ollama
Date: Wed, 1 Apr 2026 21:17:00 +0000
Subject: [PATCH 12/13] fix: Use file-based session until database is migrated
- Prevents circular dependency where login requires session, but session requires database table created by migrations
- Fresh installs: use file session until migrations run, then switch to database session
- Upgrades: use file session during migration, then switch to database session
- Simplified: removed DDL from Load_config, migrations remain source of truth
Fixes: Sessions table missing on fresh install prevents login
Addresses CodeRabbit feedback:
- Remove duplicate session table DDL (migrations are source of truth)
- Remove MySQL-specific information_schema query
- Use proper session config cloning to avoid modifying shared config
---
app/Events/Load_config.php | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/app/Events/Load_config.php b/app/Events/Load_config.php
index dc7805e64..974330ddf 100644
--- a/app/Events/Load_config.php
+++ b/app/Events/Load_config.php
@@ -4,6 +4,8 @@ namespace App\Events;
use App\Libraries\MY_Migration;
use App\Models\Appconfig;
+use CodeIgniter\Session\Handlers\DatabaseHandler;
+use CodeIgniter\Session\Handlers\FileHandler;
use CodeIgniter\Session\Session;
use Config\OSPOS;
use Config\Services;
@@ -28,7 +30,8 @@ class Load_config
$migration_config = config('Migrations');
$migration = new MY_Migration($migration_config);
- $this->session = session();
+ // Use file-based session until database is migrated
+ $this->session = $this->createSession($migration->is_latest());
// Database Configuration
$config = config(OSPOS::class);
@@ -53,4 +56,27 @@ class Load_config
bcscale(max(2, totals_decimals() + tax_decimals()));
}
+
+ /**
+ * Creates session with appropriate handler.
+ * Uses file-based session until database is migrated, then switches to database session.
+ *
+ * This prevents a circular dependency where login requires session, but the sessions
+ * database table doesn't exist yet because migrations run after login.
+ */
+ private function createSession(bool $isDbMigrated): Session
+ {
+ $sessionConfig = config('Session');
+
+ // If database is not migrated and we're configured to use database sessions,
+ // temporarily fall back to file-based sessions to allow migrations to complete.
+ // Once migrations run, subsequent requests will use database sessions.
+ if (!$isDbMigrated && $sessionConfig->driver === DatabaseHandler::class) {
+ $sessionConfig = clone $sessionConfig;
+ $sessionConfig->driver = FileHandler::class;
+ $sessionConfig->savePath = WRITEPATH . 'session';
+ }
+
+ return Services::session($sessionConfig);
+ }
}
From 71eb8de7fe01614d252ce8dac1c85879f308f333 Mon Sep 17 00:00:00 2001
From: Ollama
Date: Thu, 2 Apr 2026 06:27:14 +0000
Subject: [PATCH 13/13] feat: Improve migration UX on login page
- Show 'Database Migration Required' heading instead of welcome message when migrations pending
- Add warning alert explaining credentials needed to authorize migration
- Change button text from 'Go' to 'Migrate' during migration flow
- Add language strings for clear migration messaging
This makes it clear to the user that they are performing a migration
authorization step (not a regular login), and will need to re-authenticate
after migrations complete.
---
app/Events/Load_config.php | 3 ++-
app/Language/en/Login.php | 3 +++
app/Views/login.php | 18 +++++++++++-------
3 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/app/Events/Load_config.php b/app/Events/Load_config.php
index 974330ddf..c08bfa857 100644
--- a/app/Events/Load_config.php
+++ b/app/Events/Load_config.php
@@ -70,7 +70,8 @@ class Load_config
// If database is not migrated and we're configured to use database sessions,
// temporarily fall back to file-based sessions to allow migrations to complete.
- // Once migrations run, subsequent requests will use database sessions.
+ // Once migrations run, the user must re-authenticate (session is destroyed in
+ // load_config() when migrations are pending).
if (!$isDbMigrated && $sessionConfig->driver === DatabaseHandler::class) {
$sessionConfig = clone $sessionConfig;
$sessionConfig->driver = FileHandler::class;
diff --git a/app/Language/en/Login.php b/app/Language/en/Login.php
index 0eb94004e..000360dea 100644
--- a/app/Language/en/Login.php
+++ b/app/Language/en/Login.php
@@ -9,6 +9,9 @@ return [
"login" => "Login",
"logout" => "Logout",
"migration_needed" => "A database migration to {0} will start after login.",
+ "migration_required" => "Database Migration Required",
+ "migration_auth_message" => "Administrator credentials are required to authorize the database migration to version {0}. Please login to proceed.",
+ "migration_complete_redirect" => "Migration complete. Redirecting to login...",
"password" => "Password",
"required_username" => "The username field is required.",
"username" => "Username",
diff --git a/app/Views/login.php b/app/Views/login.php
index b7c32ce45..b79e8c89f 100644
--- a/app/Views/login.php
+++ b/app/Views/login.php
@@ -47,7 +47,14 @@
= form_open('login') ?>
- = lang('Login.welcome', [lang('Common.software_short')]) ?>
+
+ = lang('Login.migration_required') ?>
+
+ = lang('Login.migration_auth_message', [$latest_version]) ?>
+
+
+ = lang('Login.welcome', [lang('Common.software_short')]) ?>
+
getErrors() as $error): ?>
@@ -55,11 +62,6 @@
-
-
- = lang('Login.migration_needed', [$latest_version]) ?>
-
-