feat: initial scaffold with component, system plugin, and webservices plugin
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
; Authored-by: Moko Consulting
|
||||
|
||||
PLG_SYSTEM_MOKOSUITEFIELD="System - MokoSuite Field"
|
||||
PLG_SYSTEM_MOKOSUITEFIELD_DESCRIPTION="Field service management system plugin for MokoSuite."
|
||||
PLG_SYSTEM_MOKOSUITEFIELD_PARAM_COMPANY_NAME="Company Name"
|
||||
PLG_SYSTEM_MOKOSUITEFIELD_PARAM_SERVICE_RADIUS="Service Radius (km)"
|
||||
PLG_SYSTEM_MOKOSUITEFIELD_PARAM_AUTO_DISPATCH="Auto-dispatch"
|
||||
PLG_SYSTEM_MOKOSUITEFIELD_PARAM_TIMEOUT_MINUTES="Dispatch Timeout (minutes)"
|
||||
PLG_SYSTEM_MOKOSUITEFIELD_PARAM_DEFAULT_HOURLY_RATE="Default Hourly Rate"
|
||||
PLG_SYSTEM_MOKOSUITEFIELD_PARAM_TAX_RATE="Tax Rate (%)"
|
||||
PLG_SYSTEM_MOKOSUITEFIELD_PARAM_LOW_STOCK_THRESHOLD="Low Stock Threshold"
|
||||
@@ -0,0 +1,6 @@
|
||||
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
; Authored-by: Moko Consulting
|
||||
|
||||
PLG_SYSTEM_MOKOSUITEFIELD="System - MokoSuite Field"
|
||||
PLG_SYSTEM_MOKOSUITEFIELD_DESCRIPTION="Field service management system plugin for MokoSuite."
|
||||
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
Authored-by: Moko Consulting
|
||||
-->
|
||||
<extension type="plugin" group="system" method="upgrade">
|
||||
<name>plg_system_mokosuitefield</name>
|
||||
<version>0.1.0</version>
|
||||
<creationDate>2026-06-27</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<copyright>Copyright (C) 2026 Moko Consulting</copyright>
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<description>PLG_SYSTEM_MOKOSUITEFIELD_DESCRIPTION</description>
|
||||
|
||||
<namespace path="src">Moko\Plugin\System\MokoSuiteField</namespace>
|
||||
|
||||
<files>
|
||||
<folder>src</folder>
|
||||
<folder>services</folder>
|
||||
<folder>sql</folder>
|
||||
<folder>language</folder>
|
||||
</files>
|
||||
|
||||
<install>
|
||||
<sql><file driver="mysql" charset="utf8">sql/install.sql</file></sql>
|
||||
</install>
|
||||
<uninstall>
|
||||
<sql><file driver="mysql" charset="utf8">sql/uninstall.sql</file></sql>
|
||||
</uninstall>
|
||||
|
||||
<languages folder="language">
|
||||
<language tag="en-GB">en-GB/plg_system_mokosuitefield.ini</language>
|
||||
<language tag="en-GB">en-GB/plg_system_mokosuitefield.sys.ini</language>
|
||||
</languages>
|
||||
|
||||
<config>
|
||||
<fields name="params">
|
||||
<fieldset name="basic">
|
||||
<field
|
||||
name="company_name"
|
||||
type="text"
|
||||
label="PLG_SYSTEM_MOKOSUITEFIELD_PARAM_COMPANY_NAME"
|
||||
default=""
|
||||
/>
|
||||
<field
|
||||
name="service_radius"
|
||||
type="number"
|
||||
label="PLG_SYSTEM_MOKOSUITEFIELD_PARAM_SERVICE_RADIUS"
|
||||
default="50"
|
||||
min="1"
|
||||
step="1"
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset name="dispatch">
|
||||
<field
|
||||
name="auto_dispatch"
|
||||
type="list"
|
||||
label="PLG_SYSTEM_MOKOSUITEFIELD_PARAM_AUTO_DISPATCH"
|
||||
default="0"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
<field
|
||||
name="timeout_minutes"
|
||||
type="number"
|
||||
label="PLG_SYSTEM_MOKOSUITEFIELD_PARAM_TIMEOUT_MINUTES"
|
||||
default="30"
|
||||
min="1"
|
||||
step="1"
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset name="billing">
|
||||
<field
|
||||
name="default_hourly_rate"
|
||||
type="number"
|
||||
label="PLG_SYSTEM_MOKOSUITEFIELD_PARAM_DEFAULT_HOURLY_RATE"
|
||||
default="75.00"
|
||||
min="0"
|
||||
step="0.01"
|
||||
/>
|
||||
<field
|
||||
name="tax_rate"
|
||||
type="number"
|
||||
label="PLG_SYSTEM_MOKOSUITEFIELD_PARAM_TAX_RATE"
|
||||
default="0.00"
|
||||
min="0"
|
||||
step="0.01"
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset name="parts">
|
||||
<field
|
||||
name="low_stock_threshold"
|
||||
type="number"
|
||||
label="PLG_SYSTEM_MOKOSUITEFIELD_PARAM_LOW_STOCK_THRESHOLD"
|
||||
default="5"
|
||||
min="0"
|
||||
step="1"
|
||||
/>
|
||||
</fieldset>
|
||||
</fields>
|
||||
</config>
|
||||
</extension>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
* @license GPL-3.0-or-later
|
||||
* @author Moko Consulting
|
||||
*/
|
||||
|
||||
\defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Extension\PluginInterface;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
use Joomla\Event\DispatcherInterface;
|
||||
use Moko\Plugin\System\MokoSuiteField\Extension\MokoSuiteField;
|
||||
|
||||
return new class () implements ServiceProviderInterface {
|
||||
public function register(Container $container): void
|
||||
{
|
||||
$container->set(
|
||||
PluginInterface::class,
|
||||
function (Container $container) {
|
||||
$dispatcher = $container->get(DispatcherInterface::class);
|
||||
$plugin = new MokoSuiteField(
|
||||
$dispatcher,
|
||||
(array) PluginHelper::getPlugin('system', 'mokosuitefield')
|
||||
);
|
||||
$plugin->setApplication(Factory::getApplication());
|
||||
|
||||
return $plugin;
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,170 @@
|
||||
-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-- Authored-by: Moko Consulting
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokosuitefield_technicians` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`contact_id` INT DEFAULT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`email` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`phone` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`skills` VARCHAR(500) NOT NULL DEFAULT '',
|
||||
`hourly_rate` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||
`status` ENUM('active','inactive','on_leave','training') NOT NULL DEFAULT 'active',
|
||||
`current_lat` DECIMAL(10,7) DEFAULT NULL,
|
||||
`current_lng` DECIMAL(10,7) DEFAULT NULL,
|
||||
`published` TINYINT NOT NULL DEFAULT 1,
|
||||
`created` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_contact` (`contact_id`),
|
||||
KEY `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokosuitefield_equipment` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`customer_contact_id` INT DEFAULT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`equipment_type` ENUM('hvac','plumbing','electrical','appliance','generator','elevator','fire_system','other') NOT NULL DEFAULT 'other',
|
||||
`brand` VARCHAR(100) NOT NULL DEFAULT '',
|
||||
`model` VARCHAR(100) NOT NULL DEFAULT '',
|
||||
`serial_number` VARCHAR(100) NOT NULL DEFAULT '',
|
||||
`install_date` DATE DEFAULT NULL,
|
||||
`warranty_expiry` DATE DEFAULT NULL,
|
||||
`location_address` VARCHAR(500) NOT NULL DEFAULT '',
|
||||
`notes` TEXT,
|
||||
`published` TINYINT NOT NULL DEFAULT 1,
|
||||
`created` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_customer` (`customer_contact_id`),
|
||||
KEY `idx_type` (`equipment_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokosuitefield_equipment_history` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`equipment_id` INT UNSIGNED NOT NULL,
|
||||
`work_order_id` INT UNSIGNED DEFAULT NULL,
|
||||
`action` ENUM('install','repair','maintenance','inspection','replacement','decommission') NOT NULL DEFAULT 'maintenance',
|
||||
`description` VARCHAR(500) NOT NULL DEFAULT '',
|
||||
`technician_id` INT UNSIGNED DEFAULT NULL,
|
||||
`action_date` DATE NOT NULL,
|
||||
`cost` DECIMAL(10,2) DEFAULT NULL,
|
||||
`created` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_equipment` (`equipment_id`),
|
||||
KEY `idx_date` (`action_date`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokosuitefield_work_orders` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`work_order_ref` VARCHAR(20) NOT NULL,
|
||||
`customer_contact_id` INT DEFAULT NULL,
|
||||
`customer_name` VARCHAR(255) NOT NULL,
|
||||
`customer_phone` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`equipment_id` INT UNSIGNED DEFAULT NULL,
|
||||
`technician_id` INT UNSIGNED DEFAULT NULL,
|
||||
`status` ENUM('requested','scheduled','dispatched','in_progress','on_hold','completed','invoiced','cancelled') NOT NULL DEFAULT 'requested',
|
||||
`priority` ENUM('emergency','high','normal','low') NOT NULL DEFAULT 'normal',
|
||||
`work_type` ENUM('repair','maintenance','installation','inspection','warranty','callback') NOT NULL DEFAULT 'repair',
|
||||
`title` VARCHAR(255) NOT NULL,
|
||||
`description` TEXT,
|
||||
`site_address` VARCHAR(500) NOT NULL,
|
||||
`site_lat` DECIMAL(10,7) DEFAULT NULL,
|
||||
`site_lng` DECIMAL(10,7) DEFAULT NULL,
|
||||
`scheduled_date` DATE DEFAULT NULL,
|
||||
`dispatched_at` DATETIME DEFAULT NULL,
|
||||
`completed_at` DATETIME DEFAULT NULL,
|
||||
`labor_hours` DECIMAL(5,2) NOT NULL DEFAULT 0.00,
|
||||
`labor_cost` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||
`parts_cost` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||
`total_cost` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||
`customer_signature` TEXT,
|
||||
`notes` TEXT,
|
||||
`created` DATETIME NOT NULL,
|
||||
`created_by` INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_ref` (`work_order_ref`),
|
||||
KEY `idx_customer` (`customer_contact_id`),
|
||||
KEY `idx_technician` (`technician_id`),
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_scheduled` (`scheduled_date`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokosuitefield_parts` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`part_number` VARCHAR(100) NOT NULL DEFAULT '',
|
||||
`category` VARCHAR(100) NOT NULL DEFAULT '',
|
||||
`unit_cost` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||
`sell_price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||
`stock_qty` INT NOT NULL DEFAULT 0,
|
||||
`reorder_level` INT UNSIGNED NOT NULL DEFAULT 5,
|
||||
`supplier` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`published` TINYINT NOT NULL DEFAULT 1,
|
||||
`created` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_part_number` (`part_number`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokosuitefield_truck_inventory` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`technician_id` INT UNSIGNED NOT NULL,
|
||||
`part_id` INT UNSIGNED NOT NULL,
|
||||
`quantity` INT NOT NULL DEFAULT 0,
|
||||
`last_restocked` DATE DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_tech_part` (`technician_id`, `part_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokosuitefield_checklists` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`work_type` ENUM('repair','maintenance','installation','inspection','warranty','callback','all') NOT NULL DEFAULT 'all',
|
||||
`published` TINYINT NOT NULL DEFAULT 1,
|
||||
`ordering` INT NOT NULL DEFAULT 0,
|
||||
`created` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokosuitefield_checklist_items` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`checklist_id` INT UNSIGNED NOT NULL,
|
||||
`label` VARCHAR(255) NOT NULL,
|
||||
`item_type` ENUM('checkbox','text','number','photo','pass_fail') NOT NULL DEFAULT 'checkbox',
|
||||
`required` TINYINT NOT NULL DEFAULT 0,
|
||||
`ordering` INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_checklist` (`checklist_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokosuitefield_pm_agreements` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`customer_contact_id` INT NOT NULL,
|
||||
`equipment_id` INT UNSIGNED DEFAULT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`frequency` ENUM('monthly','quarterly','semi_annual','annual') NOT NULL DEFAULT 'annual',
|
||||
`next_service_date` DATE DEFAULT NULL,
|
||||
`annual_price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||
`status` ENUM('active','expired','cancelled') NOT NULL DEFAULT 'active',
|
||||
`start_date` DATE NOT NULL,
|
||||
`end_date` DATE DEFAULT NULL,
|
||||
`auto_renew` TINYINT NOT NULL DEFAULT 1,
|
||||
`created` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_customer` (`customer_contact_id`),
|
||||
KEY `idx_next_service` (`next_service_date`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokosuitefield_dispatches` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`work_order_id` INT UNSIGNED NOT NULL,
|
||||
`technician_id` INT UNSIGNED NOT NULL,
|
||||
`status` ENUM('offered','accepted','rejected','expired','cancelled') NOT NULL DEFAULT 'offered',
|
||||
`offered_at` DATETIME NOT NULL,
|
||||
`responded_at` DATETIME DEFAULT NULL,
|
||||
`distance_km` DECIMAL(10,2) DEFAULT NULL,
|
||||
`eta_minutes` DECIMAL(10,2) DEFAULT NULL,
|
||||
`attempt_number` TINYINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_work_order` (`work_order_id`),
|
||||
KEY `idx_technician` (`technician_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
@@ -0,0 +1,14 @@
|
||||
-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-- Authored-by: Moko Consulting
|
||||
|
||||
DROP TABLE IF EXISTS `#__mokosuitefield_dispatches`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitefield_pm_agreements`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitefield_checklist_items`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitefield_checklists`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitefield_truck_inventory`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitefield_parts`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitefield_work_orders`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitefield_equipment_history`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitefield_equipment`;
|
||||
DROP TABLE IF EXISTS `#__mokosuitefield_technicians`;
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
* @license GPL-3.0-or-later
|
||||
* @author Moko Consulting
|
||||
*/
|
||||
|
||||
namespace Moko\Plugin\System\MokoSuiteField\Extension;
|
||||
|
||||
use Joomla\CMS\Plugin\CMSPlugin;
|
||||
use Joomla\Event\DispatcherInterface;
|
||||
use Joomla\Event\SubscriberInterface;
|
||||
|
||||
\defined('_JEXEC') or die;
|
||||
|
||||
final class MokoSuiteField extends CMSPlugin implements SubscriberInterface
|
||||
{
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user