diff --git a/app/Config/Autoload.php b/app/Config/Autoload.php
index 87c815f8f..14e19d979 100644
--- a/app/Config/Autoload.php
+++ b/app/Config/Autoload.php
@@ -205,6 +205,7 @@ class Autoload extends AutoloadConfig
'cookie',
'tabular',
'locale',
- 'security'
+ 'security',
+ 'plugin'
];
}
diff --git a/app/Helpers/plugin_helper.php b/app/Helpers/plugin_helper.php
new file mode 100644
index 000000000..e241d2d79
--- /dev/null
+++ b/app/Helpers/plugin_helper.php
@@ -0,0 +1,27 @@
+ is_string($r)));
+ }
+
+ return is_string($results) ? $results : '';
+ }
+}
+
+if (!function_exists('plugin_content_exists'))
+{
+ function plugin_content_exists(string $section): bool
+ {
+ $observers = Events::listRegistered("view:{$section}");
+ return !empty($observers);
+ }
+}
\ No newline at end of file
diff --git a/app/Plugins/CasposPlugin/CasposPlugin.php b/app/Plugins/CasposPlugin/CasposPlugin.php
new file mode 100644
index 000000000..c95b6c526
--- /dev/null
+++ b/app/Plugins/CasposPlugin/CasposPlugin.php
@@ -0,0 +1,127 @@
+log('debug', 'CASPOS plugin events registered');
+ }
+
+ public function install(): bool
+ {
+ $this->log('info', 'Installing CASPOS plugin');
+
+ $this->setSetting('api_url', '');
+ $this->setSetting('api_key', '');
+ $this->setSetting('merchant_id', '');
+ $this->setSetting('show_receipt_button', '1');
+
+ return true;
+ }
+
+ public function uninstall(): bool
+ {
+ $this->log('info', 'Uninstalling CASPOS plugin');
+ return true;
+ }
+
+ public function getConfigView(): ?string
+ {
+ return 'Plugins/CasposPlugin/Views/config';
+ }
+
+ public function getSettings(): array
+ {
+ return [
+ 'api_url' => $this->getSetting('api_url', ''),
+ 'api_key' => $this->getSetting('api_key', ''),
+ 'merchant_id' => $this->getSetting('merchant_id', ''),
+ 'show_receipt_button' => $this->getSetting('show_receipt_button', '1'),
+ ];
+ }
+
+ public function saveSettings(array $settings): bool
+ {
+ if (isset($settings['api_url']))
+ {
+ $this->setSetting('api_url', $settings['api_url']);
+ }
+
+ if (isset($settings['api_key']))
+ {
+ $this->setSetting('api_key', $settings['api_key']);
+ }
+
+ if (isset($settings['merchant_id']))
+ {
+ $this->setSetting('merchant_id', $settings['merchant_id']);
+ }
+
+ if (isset($settings['show_receipt_button']))
+ {
+ $this->setSetting('show_receipt_button', $settings['show_receipt_button'] ? '1' : '0');
+ }
+
+ return true;
+ }
+
+ public function onItemSale(array $saleData): void
+ {
+ if (!$this->isEnabled())
+ {
+ return;
+ }
+
+ $this->log('info', "CASPOS: Processing sale {$saleData['sale_id_num']}");
+ }
+
+ public function injectReceiptButton(array $data): string
+ {
+ if (!$this->isEnabled() || $this->getSetting('show_receipt_button', '1') !== '1')
+ {
+ return '';
+ }
+
+ return view('Plugins/CasposPlugin/Views/receipt_button', $data);
+ }
+
+ public function injectCustomerTab(array $data): string
+ {
+ if (!$this->isEnabled())
+ {
+ return '';
+ }
+
+ return view('Plugins/CasposPlugin/Views/customer_tab', $data);
+ }
+}
\ No newline at end of file
diff --git a/app/Plugins/CasposPlugin/Views/config.php b/app/Plugins/CasposPlugin/Views/config.php
new file mode 100644
index 000000000..fb88a7b28
--- /dev/null
+++ b/app/Plugins/CasposPlugin/Views/config.php
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/Plugins/CasposPlugin/Views/customer_tab.php b/app/Plugins/CasposPlugin/Views/customer_tab.php
new file mode 100644
index 000000000..862828b12
--- /dev/null
+++ b/app/Plugins/CasposPlugin/Views/customer_tab.php
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/app/Plugins/CasposPlugin/Views/receipt_button.php b/app/Plugins/CasposPlugin/Views/receipt_button.php
new file mode 100644
index 000000000..a59bff4cc
--- /dev/null
+++ b/app/Plugins/CasposPlugin/Views/receipt_button.php
@@ -0,0 +1,4 @@
+
+
+ = esc(lang('Plugins.caspos_print_receipt') ?? 'Print Fiscal Receipt') ?>
+
\ No newline at end of file
diff --git a/app/Plugins/README.md b/app/Plugins/README.md
index 0c4137154..1cad1a60d 100644
--- a/app/Plugins/README.md
+++ b/app/Plugins/README.md
@@ -100,6 +100,123 @@ OSPOS fires these events that plugins can listen to:
| `items_csv_import` | `array $importData` | Fired after items CSV import |
| `customers_csv_import` | `array $importData` | Fired after customers CSV import |
+## View Hooks (Injecting Plugin Content into Views)
+
+Plugins can inject UI elements into core views using the event-based view hook system. This allows plugins to add buttons, tabs, or other content without modifying core view files.
+
+### How It Works
+
+1. **Core views define hook points** using the `plugin_content()` helper
+2. **Plugins register listeners** for these view hooks in `registerEvents()`
+3. **Content is conditionally rendered** only if the plugin is enabled
+
+### Step 1: Adding Hook Points in Core Views
+
+In your core view files, use the `plugin_content()` helper to define injection points:
+
+```php
+// In app/Views/sales/receipt.php
+