diff --git a/LICENSE b/LICENSE
index b06866a..bc3b5f2 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2017 WHMCS, Limited
+Copyright (c) 2017 WHMCS, Limited, 2023 Kumi Systems e.U.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 0310f6d..1ad239f 100644
--- a/README.md
+++ b/README.md
@@ -1,32 +1,14 @@
-# WHMCS Sample Addon Module #
+# Account Selection Module for WHMCS
-## Summary ##
+## Summary
-An addon module allows you to add additional functionality to WHMCS. It
-can provide both client and admin facing user interfaces, as well as
-utilise hook functionality within WHMCS.
+This module allows you to select the account that you want a specific invoice item to be assigned to in accounting.
-This sample file demonstrates how an addon module for WHMCS should be
-structured and exercises all supported functionality.
+This was a specific requirement for a client, but the concept of displaying a dynamic list of values for a custom invoice item field may be useful to others.
-For more information, please refer to the online documentation at
-https://developers.whmcs.com/addon-modules/
+This addon is a fork of the [WHMCS Sample Addon Module](https://github.com/WHMCS/sample-addon-module) and, as such, is licensed under the MIT License.
-## Recommended Module Content ##
-
-The recommended structure of an addon module is as follows.
-
-```
- addonmodule/
- |- lang/
- |- lib/
- |- templates/
- | addonmodule.php
- | hooks.php
- | logo.png
-```
-
-## Minimum Requirements ##
+## Minimum Requirements
For the latest WHMCS minimum system requirements, please refer to
http://docs.whmcs.com/System_Requirements
@@ -34,14 +16,7 @@ http://docs.whmcs.com/System_Requirements
We recommend your module follows the same minimum requirements wherever
possible.
-## Tests ##
+## License
-We strongly encourage you to write unit tests for your work. Within this SDK we
-provide a sample unit test based upon the widely used PHPUnit.
-
-## Useful Resources
-* [Developer Portal](https://developers.whmcs.com/)
-* [Hook Documentation](https://developers.whmcs.com/hooks/)
-* [API Documentation](https://developers.whmcs.com/api/)
-
-[WHMCS Limited](https://www.whmcs.com)
+This module is licensed under the MIT License. Please see the LICENSE file for
+more information.
\ No newline at end of file
diff --git a/composer.json b/composer.json
deleted file mode 100644
index 7248aa8..0000000
--- a/composer.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "name": "whmcs/sample-addon-module",
- "description": "Sample Addon Module for WHMCS Billing Automation Platform",
- "keywords": [
- "whmcs",
- "web host automation platform",
- "addon module"
- ],
- "homepage": "http://www.whmcs.com/",
- "license": "MIT",
- "authors": [
- {
- "name": "WHMCS Development Team",
- "email": "development@whmcs.com",
- "homepage": "http://www.whmcs.com/",
- "role": "Developer"
- }
- ],
- "support": {
- "email": "support@whmcs.com",
- "forum": "http://forums.whmcs.com/",
- "wiki": "http://docs.whmcs.com/"
- },
- "require-dev": {
- "phpunit/phpunit": "@stable"
- }
-}
diff --git a/modules/addons/accounting/accounting.php b/modules/addons/accounting/accounting.php
new file mode 100644
index 0000000..f8e4a01
--- /dev/null
+++ b/modules/addons/accounting/accounting.php
@@ -0,0 +1,152 @@
+ 'Account Selector',
+ // Description displayed within the admin interface
+ 'description' => 'This module allows you to select the account to be used for a given invoice item in accounting.',
+ // Module author name
+ 'author' => 'Kumi Systems e.U.',
+ // Default language
+ 'language' => 'english',
+ // Version number
+ 'version' => '1.0',
+ 'fields' => [
+ 'Available Accounts' => [
+ 'FriendlyName' => 'Available Accounts',
+ 'Type' => 'textarea',
+ 'Rows' => '20',
+ 'Cols' => '100',
+ 'Default' => '1234 - Example Account',
+ 'Description' => 'List of available accounts, one per line. Format: Account Number - Account Name',
+ ],
+ ]
+ ];
+}
+
+/**
+ * Called upon activation of the module for the first time.
+ * Used to create database tables required by the module.
+ *
+ * @see https://developers.whmcs.com/advanced/db-interaction/
+ *
+ * @return array Optional success/failure message
+ */
+function accounting_activate()
+{
+ try {
+ Capsule::schema()
+ ->create(
+ 'mod_accounting',
+ function ($table) {
+ /** @var \Illuminate\Database\Schema\Blueprint $table */
+ $table->increments('id');
+ $table->integer('invoice');
+ $table->integer('item');
+ $table->text('account');
+ }
+ );
+
+ return [
+ 'status' => 'success',
+ 'description' => 'Successfully created mod_accounting table. Now, please set up your accounts in the module configuration.',
+ ];
+ } catch (\Exception $e) {
+ return [
+ 'status' => "error",
+ 'description' => 'Unable to create mod_accounting: ' . $e->getMessage(),
+ ];
+ }
+}
+
+/**
+ * Deactivate.
+ *
+ * Called upon deactivation of the module.
+ * Used to drop database tables created by the module.
+ *
+ * @return array Optional success/failure message
+ */
+function accounting_deactivate()
+{
+ try {
+ Capsule::schema()
+ ->dropIfExists('mod_accounting');
+
+ return [
+ 'status' => 'success',
+ 'description' => 'Dropped mod_accounting table.',
+ ];
+ } catch (\Exception $e) {
+ return [
+ // Supported values here include: success, error or info
+ "status" => "error",
+ "description" => "Unable to drop mod_accounting: {$e->getMessage()}",
+ ];
+ }
+}
+
+/**
+ * Admin Area Output.
+ *
+ * Called when the addon module is accessed via the admin area.
+ * Should return HTML output for display to the admin user.
+ *
+ * This function is optional.
+ *
+ * @see AddonModule\Admin\Controller::index()
+ *
+ * @return string
+ */
+function accounting_output($vars)
+{
+ // Get common module parameters
+ $modulelink = $vars['modulelink'];
+ $version = $vars['version'];
+ $_lang = $vars['_lang']; // an array of the currently loaded language variables
+
+ // Get module configuration parameters
+ $configTextareaField = $vars['Available Accounts'];
+
+ // Dispatch and handle request here. What follows is a demonstration of one
+ // possible way of handling this using a very basic dispatcher implementation.
+
+ $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
+
+ $dispatcher = new AdminDispatcher();
+ $response = $dispatcher->dispatch($action, $vars);
+ echo $response;
+}
diff --git a/modules/addons/accounting/hooks.php b/modules/addons/accounting/hooks.php
new file mode 100644
index 0000000..9e86cb4
--- /dev/null
+++ b/modules/addons/accounting/hooks.php
@@ -0,0 +1,56 @@
+where('invoiceid', $invoiceId)
+ ->get();
+ // Get the available accounts from the module configuration.
+ $availableAccounts = explode("\n", $params['Available Accounts']);
+ // Create the drop-down field for each invoice item.
+ foreach ($invoiceItems as $invoiceItem) {
+ $accountSelector = '';
+ // Add the drop-down field to the invoice item.
+ echo '';
+ }
+ } catch (Exception $e) {
+ // Consider logging or reporting the error.
+ }
+});
+
+add_hook('ClientEdit', 1, function(array $params) {
+ try {
+ // Call the service's function, using the values provided by WHMCS in
+ // `$params`.
+ } catch (Exception $e) {
+ // Consider logging or reporting the error.
+ }
+});
diff --git a/modules/addons/addonmodule/lang/english.php b/modules/addons/accounting/lang/english.php
similarity index 100%
rename from modules/addons/addonmodule/lang/english.php
rename to modules/addons/accounting/lang/english.php
diff --git a/modules/addons/addonmodule/lib/Admin/AdminDispatcher.php b/modules/addons/accounting/lib/Admin/AdminDispatcher.php
similarity index 100%
rename from modules/addons/addonmodule/lib/Admin/AdminDispatcher.php
rename to modules/addons/accounting/lib/Admin/AdminDispatcher.php
diff --git a/modules/addons/addonmodule/lib/Admin/Controller.php b/modules/addons/accounting/lib/Admin/Controller.php
similarity index 68%
rename from modules/addons/addonmodule/lib/Admin/Controller.php
rename to modules/addons/accounting/lib/Admin/Controller.php
index 0c13dcc..023c867 100644
--- a/modules/addons/addonmodule/lib/Admin/Controller.php
+++ b/modules/addons/accounting/lib/Admin/Controller.php
@@ -22,12 +22,7 @@ class Controller {
$LANG = $vars['_lang']; // an array of the currently loaded language variables
// Get module configuration parameters
- $configTextField = $vars['Text Field Name'];
- $configPasswordField = $vars['Password Field Name'];
- $configCheckboxField = $vars['Checkbox Field Name'];
- $configDropdownField = $vars['Dropdown Field Name'];
- $configRadioField = $vars['Radio Field Name'];
- $configTextareaField = $vars['Textarea Field Name'];
+ $configTextareaField = $vars['Available Accounts'];
return <<
- Text Field: {$configTextField}@@ -77,12 +67,7 @@ EOF; $LANG = $vars['_lang']; // an array of the currently loaded language variables // Get module configuration parameters - $configTextField = $vars['Text Field Name']; - $configPasswordField = $vars['Password Field Name']; - $configCheckboxField = $vars['Checkbox Field Name']; - $configDropdownField = $vars['Dropdown Field Name']; - $configRadioField = $vars['Radio Field Name']; - $configTextareaField = $vars['Textarea Field Name']; + $configTextareaField = $vars['Available Accounts']; return <<
- Password Field: {$configPasswordField}
- Checkbox Field: {$configCheckboxField}
- Dropdown Field: {$configDropdownField}
- Radio Field: {$configRadioField}
Textarea Field: {$configTextareaField}
Sidebar output HTML goes here
'; - return $sidebar; -} - -/** - * Client Area Output. - * - * Called when the addon module is accessed via the client area. - * Should return an array of output parameters. - * - * This function is optional. - * - * @see AddonModule\Client\Controller::index() - * - * @return array - */ -function addonmodule_clientarea($vars) -{ - // Get common module parameters - $modulelink = $vars['modulelink']; // eg. index.php?m=addonmodule - $version = $vars['version']; // eg. 1.0 - $_lang = $vars['_lang']; // an array of the currently loaded language variables - - // Get module configuration parameters - $configTextField = $vars['Text Field Name']; - $configPasswordField = $vars['Password Field Name']; - $configCheckboxField = $vars['Checkbox Field Name']; - $configDropdownField = $vars['Dropdown Field Name']; - $configRadioField = $vars['Radio Field Name']; - $configTextareaField = $vars['Textarea Field Name']; - - /** - * Dispatch and handle request here. What follows is a demonstration of one - * possible way of handling this using a very basic dispatcher implementation. - */ - - $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : ''; - - $dispatcher = new ClientDispatcher(); - return $dispatcher->dispatch($action, $vars); -} diff --git a/modules/addons/addonmodule/hooks.php b/modules/addons/addonmodule/hooks.php deleted file mode 100644 index d6924e8..0000000 --- a/modules/addons/addonmodule/hooks.php +++ /dev/null @@ -1,38 +0,0 @@ -$action($parameters); - } - } -} diff --git a/modules/addons/addonmodule/lib/Client/Controller.php b/modules/addons/addonmodule/lib/Client/Controller.php deleted file mode 100644 index 0cddf88..0000000 --- a/modules/addons/addonmodule/lib/Client/Controller.php +++ /dev/null @@ -1,86 +0,0 @@ - 'Sample Addon Module', - 'breadcrumb' => array( - 'index.php?m=addonmodule' => 'Sample Addon Module', - ), - 'templatefile' => 'publicpage', - 'requirelogin' => false, // Set true to restrict access to authenticated client users - 'forcessl' => false, // Deprecated as of Version 7.0. Requests will always use SSL if available. - 'vars' => array( - 'modulelink' => $modulelink, - 'configTextField' => $configTextField, - 'customVariable' => 'your own content goes here', - ), - ); - } - - /** - * Secret action. - * - * @param array $vars Module configuration parameters - * - * @return array - */ - public function secret($vars) - { - // Get common module parameters - $modulelink = $vars['modulelink']; // eg. addonmodules.php?module=addonmodule - $version = $vars['version']; // eg. 1.0 - $LANG = $vars['_lang']; // an array of the currently loaded language variables - - // Get module configuration parameters - $configTextField = $vars['Text Field Name']; - $configPasswordField = $vars['Password Field Name']; - $configCheckboxField = $vars['Checkbox Field Name']; - $configDropdownField = $vars['Dropdown Field Name']; - $configRadioField = $vars['Radio Field Name']; - $configTextareaField = $vars['Textarea Field Name']; - - return array( - 'pagetitle' => 'Sample Addon Module', - 'breadcrumb' => array( - 'index.php?m=addonmodule' => 'Sample Addon Module', - 'index.php?m=addonmodule&action=secret' => 'Secret Page', - ), - 'templatefile' => 'secretpage', - 'requirelogin' => true, // Set true to restrict access to authenticated client users - 'forcessl' => false, // Deprecated as of Version 7.0. Requests will always use SSL if available. - 'vars' => array( - 'modulelink' => $modulelink, - 'configTextField' => $configTextField, - 'customVariable' => 'your own content goes here', - ), - ); - } -} diff --git a/modules/addons/addonmodule/templates/js/sample.js b/modules/addons/addonmodule/templates/js/sample.js deleted file mode 100644 index e69de29..0000000 diff --git a/modules/addons/addonmodule/templates/publicpage.tpl b/modules/addons/addonmodule/templates/publicpage.tpl deleted file mode 100644 index 3ff831e..0000000 --- a/modules/addons/addonmodule/templates/publicpage.tpl +++ /dev/null @@ -1,43 +0,0 @@ -This is an example of a public client area page that does not require a login to view.
- -All the template variables you define along with some additional standard template variables are available within this template.
You can use the Smarty {ldelim}debug{rdelim} function call to see a full list.
- - - Go to page that requires authentication - -
diff --git a/modules/addons/addonmodule/templates/secretpage.tpl b/modules/addons/addonmodule/templates/secretpage.tpl deleted file mode 100644 index b527be7..0000000 --- a/modules/addons/addonmodule/templates/secretpage.tpl +++ /dev/null @@ -1,45 +0,0 @@ -This is an example of a client area page that requires authentication to access.
- -You will have either been prompted to login or already have an active login state to access this page.
- -All the template variables you define along with some additional standard template variables are available within this template.
You can use the Smarty {ldelim}debug{rdelim} function call to see a full list.