Database schema (10 new tables): - erp_esign_requests/signers/events — full e-signature lifecycle with encrypted selfie/ID verification, 128-char tokens, audit trail - erp_products — lightweight catalog linked to #__content articles - erp_orders/order_items — order management with status tracking - erp_invoices/invoice_items — invoicing with standard/credit/recurring - erp_payments — payment tracking with gateway transaction IDs API controllers: - ErpSignRequestsController — signature request CRUD with signer management, auto-ref generation (SIG-YYYY-NNN), audit logging Routes registered for products, orders, invoices, payments, e-signature
This commit is contained in:
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
/**
|
||||
* @package MokoWaaS
|
||||
* @subpackage com_mokowaas
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GNU General Public License version 3 or later; see LICENSE
|
||||
*/
|
||||
|
||||
namespace Moko\Component\MokoWaaS\Api\Controller;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\MVC\Controller\BaseController;
|
||||
|
||||
/**
|
||||
* E-Signature Requests API controller.
|
||||
*
|
||||
* Manages signature request lifecycle: create, send, track, complete.
|
||||
*
|
||||
* @since 02.34.16
|
||||
*/
|
||||
class ErpSignRequestsController extends BaseController
|
||||
{
|
||||
/**
|
||||
* List signature requests.
|
||||
*/
|
||||
public function displayList(): void
|
||||
{
|
||||
$this->requireAuth();
|
||||
|
||||
$db = Factory::getDbo();
|
||||
$input = Factory::getApplication()->getInput();
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select('r.*, cd.name AS contact_name')
|
||||
->select('(SELECT COUNT(*) FROM ' . $db->quoteName('#__mokowaas_erp_esign_signers') . ' s WHERE s.request_id = r.id) AS signer_count')
|
||||
->select('(SELECT COUNT(*) FROM ' . $db->quoteName('#__mokowaas_erp_esign_signers') . ' s WHERE s.request_id = r.id AND s.status = ' . $db->quote('signed') . ') AS signed_count')
|
||||
->from($db->quoteName('#__mokowaas_erp_esign_requests', 'r'))
|
||||
->join('LEFT', $db->quoteName('#__contact_details', 'cd') . ' ON cd.id = r.contact_id')
|
||||
->order('r.date_creation DESC');
|
||||
|
||||
$status = $input->get('status', '', 'CMD');
|
||||
|
||||
if ($status)
|
||||
{
|
||||
$query->where($db->quoteName('r.status') . ' = ' . $db->quote($status));
|
||||
}
|
||||
|
||||
$limit = $input->getInt('limit', 50);
|
||||
$offset = $input->getInt('offset', 0);
|
||||
|
||||
$db->setQuery($query, $offset, $limit);
|
||||
|
||||
$this->sendJson(200, ['data' => $db->loadObjectList()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single request with signers and audit trail.
|
||||
*/
|
||||
public function displayItem(): void
|
||||
{
|
||||
$this->requireAuth();
|
||||
|
||||
$id = Factory::getApplication()->getInput()->getInt('id', 0);
|
||||
$db = Factory::getDbo();
|
||||
|
||||
// Request
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select('r.*, cd.name AS contact_name')
|
||||
->from($db->quoteName('#__mokowaas_erp_esign_requests', 'r'))
|
||||
->join('LEFT', $db->quoteName('#__contact_details', 'cd') . ' ON cd.id = r.contact_id')
|
||||
->where($db->quoteName('r.id') . ' = ' . $id)
|
||||
);
|
||||
|
||||
$item = $db->loadObject();
|
||||
|
||||
if (!$item)
|
||||
{
|
||||
$this->sendJson(404, ['error' => 'Signature request not found']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Signers (exclude encrypted verification data from list view)
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select('id, request_id, role, email, firstname, lastname, status, position, date_sent, date_viewed, date_signed, ip_address, geo_country, geo_city')
|
||||
->from($db->quoteName('#__mokowaas_erp_esign_signers'))
|
||||
->where($db->quoteName('request_id') . ' = ' . $id)
|
||||
->order('position ASC')
|
||||
);
|
||||
|
||||
$item->signers = $db->loadObjectList();
|
||||
|
||||
// Audit trail
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select('*')
|
||||
->from($db->quoteName('#__mokowaas_erp_esign_events'))
|
||||
->where($db->quoteName('request_id') . ' = ' . $id)
|
||||
->order('created ASC')
|
||||
);
|
||||
|
||||
$item->events = $db->loadObjectList();
|
||||
|
||||
$this->sendJson(200, ['data' => $item]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new signature request.
|
||||
*/
|
||||
public function add(): void
|
||||
{
|
||||
$this->requireAuth();
|
||||
|
||||
$input = json_decode(Factory::getApplication()->getInput()->json->getRaw(), true);
|
||||
$db = Factory::getDbo();
|
||||
$now = Factory::getDate()->toSql();
|
||||
$user = Factory::getUser();
|
||||
|
||||
$title = trim($input['title'] ?? '');
|
||||
|
||||
if (!$title)
|
||||
{
|
||||
$this->sendJson(400, ['error' => 'title is required']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate ref: SIG-YYYY-NNN
|
||||
$year = date('Y');
|
||||
$like = $db->quote('SIG-' . $year . '-%');
|
||||
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select('MAX(' . $db->quoteName('ref') . ')')
|
||||
->from($db->quoteName('#__mokowaas_erp_esign_requests'))
|
||||
->where($db->quoteName('ref') . ' LIKE ' . $like)
|
||||
);
|
||||
|
||||
$maxRef = $db->loadResult();
|
||||
$seq = $maxRef ? ((int) end(explode('-', $maxRef)) + 1) : 1;
|
||||
$ref = sprintf('SIG-%s-%03d', $year, $seq);
|
||||
|
||||
$obj = (object) [
|
||||
'ref' => $ref,
|
||||
'title' => $title,
|
||||
'description' => $input['description'] ?? null,
|
||||
'contact_id' => ($input['contact_id'] ?? null) ? (int) $input['contact_id'] : null,
|
||||
'status' => 'draft',
|
||||
'require_selfie' => (int) ($input['require_selfie'] ?? 0),
|
||||
'require_id' => (int) ($input['require_id'] ?? 0),
|
||||
'require_otp' => $input['require_otp'] ?? 'smart',
|
||||
'date_creation' => $now,
|
||||
'date_expiry' => $input['date_expiry'] ?? null,
|
||||
'created_by' => (int) $user->id,
|
||||
];
|
||||
|
||||
$db->insertObject('#__mokowaas_erp_esign_requests', $obj, 'id');
|
||||
$requestId = $db->insertid();
|
||||
|
||||
// Log creation event
|
||||
$this->logEvent($db, $requestId, null, 'CREATED', 'Signature request created', $user->id);
|
||||
|
||||
// Add signers if provided
|
||||
$signers = $input['signers'] ?? [];
|
||||
|
||||
foreach ($signers as $i => $signer)
|
||||
{
|
||||
$email = trim($signer['email'] ?? '');
|
||||
|
||||
if (!$email)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$token = bin2hex(random_bytes(64));
|
||||
|
||||
$signerObj = (object) [
|
||||
'request_id' => $requestId,
|
||||
'role' => $signer['role'] ?? '',
|
||||
'email' => $email,
|
||||
'firstname' => $signer['firstname'] ?? '',
|
||||
'lastname' => $signer['lastname'] ?? '',
|
||||
'phone' => $signer['phone'] ?? '',
|
||||
'status' => 'pending',
|
||||
'token' => $token,
|
||||
'position' => $i + 1,
|
||||
'date_creation' => $now,
|
||||
];
|
||||
|
||||
$db->insertObject('#__mokowaas_erp_esign_signers', $signerObj);
|
||||
}
|
||||
|
||||
$this->sendJson(201, ['data' => $obj, 'id' => $requestId, 'ref' => $ref]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update request status (send, cancel, etc.).
|
||||
*/
|
||||
public function edit(): void
|
||||
{
|
||||
$this->requireAuth();
|
||||
|
||||
$id = Factory::getApplication()->getInput()->getInt('id', 0);
|
||||
$input = json_decode(Factory::getApplication()->getInput()->json->getRaw(), true);
|
||||
$db = Factory::getDbo();
|
||||
$now = Factory::getDate()->toSql();
|
||||
|
||||
$allowed = ['status', 'title', 'description', 'date_expiry', 'require_selfie', 'require_id', 'require_otp'];
|
||||
$updates = [];
|
||||
|
||||
foreach ($allowed as $field)
|
||||
{
|
||||
if (isset($input[$field]))
|
||||
{
|
||||
$updates[$field] = $input[$field];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($updates))
|
||||
{
|
||||
$this->sendJson(400, ['error' => 'No valid fields to update']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Track status transitions
|
||||
if (isset($updates['status']))
|
||||
{
|
||||
$status = $updates['status'];
|
||||
|
||||
if ($status === 'pending')
|
||||
{
|
||||
$updates['date_sent'] = $now;
|
||||
}
|
||||
|
||||
$eventCode = strtoupper($status === 'pending' ? 'SENT' : $status);
|
||||
$this->logEvent($db, $id, null, $eventCode, 'Request status changed to ' . $status, Factory::getUser()->id);
|
||||
}
|
||||
|
||||
$obj = (object) array_merge(['id' => $id], $updates);
|
||||
$db->updateObject('#__mokowaas_erp_esign_requests', $obj, 'id');
|
||||
|
||||
$this->sendJson(200, ['data' => $obj]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a request and all related data.
|
||||
*/
|
||||
public function delete(): void
|
||||
{
|
||||
$this->requireAuth();
|
||||
|
||||
$id = Factory::getApplication()->getInput()->getInt('id', 0);
|
||||
$db = Factory::getDbo();
|
||||
|
||||
$tables = [
|
||||
'#__mokowaas_erp_esign_events',
|
||||
'#__mokowaas_erp_esign_signers',
|
||||
'#__mokowaas_erp_esign_requests',
|
||||
];
|
||||
|
||||
foreach ($tables as $table)
|
||||
{
|
||||
$col = $table === '#__mokowaas_erp_esign_requests' ? 'id' : 'request_id';
|
||||
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->delete($db->quoteName($table))
|
||||
->where($db->quoteName($col) . ' = ' . $id)
|
||||
);
|
||||
$db->execute();
|
||||
}
|
||||
|
||||
$this->sendJson(200, ['message' => 'Signature request deleted', 'id' => $id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an audit trail event.
|
||||
*/
|
||||
private function logEvent($db, int $requestId, ?int $signerId, string $code, string $label, ?int $userId): void
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
|
||||
$event = (object) [
|
||||
'request_id' => $requestId,
|
||||
'signer_id' => $signerId,
|
||||
'code' => $code,
|
||||
'label' => $label,
|
||||
'ip' => $app->getInput()->server->getString('REMOTE_ADDR', ''),
|
||||
'user_agent' => $app->getInput()->server->getString('HTTP_USER_AGENT', ''),
|
||||
'user_id' => $userId,
|
||||
'created' => Factory::getDate()->toSql(),
|
||||
];
|
||||
|
||||
$db->insertObject('#__mokowaas_erp_esign_events', $event);
|
||||
}
|
||||
|
||||
private function requireAuth(): void
|
||||
{
|
||||
$user = Factory::getApplication()->getIdentity();
|
||||
|
||||
if (!$user->authorise('core.manage', 'com_mokowaas'))
|
||||
{
|
||||
$this->sendJson(403, ['error' => 'Not authorized']);
|
||||
$this->app->close();
|
||||
}
|
||||
}
|
||||
|
||||
private function sendJson(int $code, array $data): void
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
$app->setHeader('Content-Type', 'application/json', true);
|
||||
$app->setHeader('Status', (string) $code, true);
|
||||
echo json_encode($data, JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
}
|
||||
@@ -101,3 +101,217 @@ CREATE TABLE IF NOT EXISTS `#__mokowaas_erp_activities` (
|
||||
KEY `idx_due_date` (`due_date`),
|
||||
KEY `idx_created` (`created`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- =============================================
|
||||
-- E-Signature Tables
|
||||
-- =============================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokowaas_erp_esign_requests` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`ref` VARCHAR(128) NOT NULL DEFAULT '',
|
||||
`title` VARCHAR(255) NOT NULL,
|
||||
`description` TEXT,
|
||||
`document_path` VARCHAR(255) DEFAULT NULL,
|
||||
`contact_id` INT DEFAULT NULL,
|
||||
`status` ENUM('draft','pending','inprogress','completed','declined','expired','cancelled') NOT NULL DEFAULT 'draft',
|
||||
`require_selfie` TINYINT NOT NULL DEFAULT 0,
|
||||
`require_id` TINYINT NOT NULL DEFAULT 0,
|
||||
`require_otp` VARCHAR(16) NOT NULL DEFAULT 'smart',
|
||||
`date_creation` DATETIME NOT NULL,
|
||||
`date_sent` DATETIME DEFAULT NULL,
|
||||
`date_signature` DATETIME DEFAULT NULL,
|
||||
`date_expiry` DATETIME DEFAULT NULL,
|
||||
`created_by` INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_ref` (`ref`),
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_contact` (`contact_id`),
|
||||
KEY `idx_expiry` (`date_expiry`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokowaas_erp_esign_signers` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`request_id` INT UNSIGNED NOT NULL,
|
||||
`role` VARCHAR(64) NOT NULL DEFAULT '',
|
||||
`email` VARCHAR(255) NOT NULL,
|
||||
`firstname` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`lastname` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`phone` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`status` ENUM('pending','viewed','signed','declined','cancelled') NOT NULL DEFAULT 'pending',
|
||||
`token` VARCHAR(128) NOT NULL,
|
||||
`signature_data` MEDIUMTEXT,
|
||||
`signature_type` VARCHAR(32) DEFAULT NULL,
|
||||
`selfie_path` VARCHAR(255) DEFAULT NULL,
|
||||
`id_path` VARCHAR(255) DEFAULT NULL,
|
||||
`ip_address` VARCHAR(64) NOT NULL DEFAULT '',
|
||||
`user_agent` TEXT,
|
||||
`geo_lat` DECIMAL(10,7) DEFAULT NULL,
|
||||
`geo_lon` DECIMAL(10,7) DEFAULT NULL,
|
||||
`geo_country` VARCHAR(100) DEFAULT NULL,
|
||||
`geo_city` VARCHAR(100) DEFAULT NULL,
|
||||
`otp_verified` TINYINT NOT NULL DEFAULT 0,
|
||||
`position` INT NOT NULL DEFAULT 0,
|
||||
`date_sent` DATETIME DEFAULT NULL,
|
||||
`date_viewed` DATETIME DEFAULT NULL,
|
||||
`date_signed` DATETIME DEFAULT NULL,
|
||||
`date_creation` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_token` (`token`),
|
||||
KEY `idx_request` (`request_id`),
|
||||
KEY `idx_email` (`email`),
|
||||
KEY `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokowaas_erp_esign_events` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`request_id` INT UNSIGNED NOT NULL,
|
||||
`signer_id` INT UNSIGNED DEFAULT NULL,
|
||||
`code` VARCHAR(64) NOT NULL,
|
||||
`label` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`description` TEXT,
|
||||
`ip` VARCHAR(64) NOT NULL DEFAULT '',
|
||||
`user_agent` TEXT,
|
||||
`user_id` INT DEFAULT NULL,
|
||||
`created` DATETIME NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_request` (`request_id`),
|
||||
KEY `idx_signer` (`signer_id`),
|
||||
KEY `idx_code` (`code`),
|
||||
KEY `idx_created` (`created`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- =============================================
|
||||
-- Products (descriptions via #__content articles)
|
||||
-- =============================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokowaas_erp_products` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`sku` VARCHAR(100) NOT NULL DEFAULT '',
|
||||
`article_id` INT DEFAULT NULL,
|
||||
`type` ENUM('product','service') NOT NULL DEFAULT 'product',
|
||||
`price` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`cost_price` DECIMAL(15,2) DEFAULT NULL,
|
||||
`tax_rate` DECIMAL(5,2) NOT NULL DEFAULT 0.00,
|
||||
`currency` VARCHAR(3) NOT NULL DEFAULT 'USD',
|
||||
`stock_qty` DECIMAL(15,4) NOT NULL DEFAULT 0.0000,
|
||||
`low_stock_threshold` INT DEFAULT NULL,
|
||||
`weight` DECIMAL(10,3) DEFAULT NULL,
|
||||
`barcode` VARCHAR(100) DEFAULT NULL,
|
||||
`category_id` INT DEFAULT NULL,
|
||||
`published` TINYINT NOT NULL DEFAULT 1,
|
||||
`created` DATETIME NOT NULL,
|
||||
`modified` DATETIME DEFAULT NULL,
|
||||
`created_by` INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_sku` (`sku`),
|
||||
KEY `idx_article` (`article_id`),
|
||||
KEY `idx_type` (`type`),
|
||||
KEY `idx_barcode` (`barcode`),
|
||||
KEY `idx_category` (`category_id`),
|
||||
KEY `idx_published` (`published`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- =============================================
|
||||
-- Orders & Invoicing
|
||||
-- =============================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokowaas_erp_orders` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`ref` VARCHAR(128) NOT NULL DEFAULT '',
|
||||
`contact_id` INT NOT NULL,
|
||||
`status` ENUM('draft','confirmed','processing','shipped','delivered','cancelled','refunded') NOT NULL DEFAULT 'draft',
|
||||
`subtotal` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`tax_total` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`total` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`currency` VARCHAR(3) NOT NULL DEFAULT 'USD',
|
||||
`payment_method` VARCHAR(50) DEFAULT NULL,
|
||||
`payment_status` ENUM('unpaid','partial','paid','refunded') NOT NULL DEFAULT 'unpaid',
|
||||
`shipping_address` TEXT,
|
||||
`notes` TEXT,
|
||||
`created` DATETIME NOT NULL,
|
||||
`modified` DATETIME DEFAULT NULL,
|
||||
`created_by` INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_ref` (`ref`),
|
||||
KEY `idx_contact` (`contact_id`),
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_payment_status` (`payment_status`),
|
||||
KEY `idx_created` (`created`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokowaas_erp_order_items` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`order_id` INT UNSIGNED NOT NULL,
|
||||
`product_id` INT UNSIGNED DEFAULT NULL,
|
||||
`description` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`quantity` DECIMAL(15,4) NOT NULL DEFAULT 1.0000,
|
||||
`unit_price` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`tax_rate` DECIMAL(5,2) NOT NULL DEFAULT 0.00,
|
||||
`line_total` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`position` INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_order` (`order_id`),
|
||||
KEY `idx_product` (`product_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokowaas_erp_invoices` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`ref` VARCHAR(128) NOT NULL DEFAULT '',
|
||||
`order_id` INT UNSIGNED DEFAULT NULL,
|
||||
`contact_id` INT NOT NULL,
|
||||
`type` ENUM('standard','credit_note','recurring') NOT NULL DEFAULT 'standard',
|
||||
`status` ENUM('draft','sent','paid','partial','overdue','cancelled','refunded') NOT NULL DEFAULT 'draft',
|
||||
`subtotal` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`tax_total` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`total` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`amount_paid` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`currency` VARCHAR(3) NOT NULL DEFAULT 'USD',
|
||||
`due_date` DATE DEFAULT NULL,
|
||||
`notes` TEXT,
|
||||
`created` DATETIME NOT NULL,
|
||||
`modified` DATETIME DEFAULT NULL,
|
||||
`paid_date` DATETIME DEFAULT NULL,
|
||||
`created_by` INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_ref` (`ref`),
|
||||
KEY `idx_order` (`order_id`),
|
||||
KEY `idx_contact` (`contact_id`),
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_due_date` (`due_date`),
|
||||
KEY `idx_created` (`created`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokowaas_erp_invoice_items` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`invoice_id` INT UNSIGNED NOT NULL,
|
||||
`product_id` INT UNSIGNED DEFAULT NULL,
|
||||
`description` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`quantity` DECIMAL(15,4) NOT NULL DEFAULT 1.0000,
|
||||
`unit_price` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`tax_rate` DECIMAL(5,2) NOT NULL DEFAULT 0.00,
|
||||
`line_total` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
|
||||
`position` INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_invoice` (`invoice_id`),
|
||||
KEY `idx_product` (`product_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `#__mokowaas_erp_payments` (
|
||||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`invoice_id` INT UNSIGNED NOT NULL,
|
||||
`amount` DECIMAL(15,2) NOT NULL,
|
||||
`currency` VARCHAR(3) NOT NULL DEFAULT 'USD',
|
||||
`method` VARCHAR(50) NOT NULL DEFAULT '',
|
||||
`reference` VARCHAR(255) DEFAULT NULL,
|
||||
`gateway` VARCHAR(50) DEFAULT NULL,
|
||||
`gateway_transaction_id` VARCHAR(255) DEFAULT NULL,
|
||||
`status` ENUM('pending','completed','failed','refunded') NOT NULL DEFAULT 'completed',
|
||||
`notes` TEXT,
|
||||
`created` DATETIME NOT NULL,
|
||||
`created_by` INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_invoice` (`invoice_id`),
|
||||
KEY `idx_status` (`status`),
|
||||
KEY `idx_gateway` (`gateway`),
|
||||
KEY `idx_created` (`created`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_payments`;
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_invoice_items`;
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_invoices`;
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_order_items`;
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_orders`;
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_products`;
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_esign_events`;
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_esign_signers`;
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_esign_requests`;
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_activities`;
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_deals`;
|
||||
DROP TABLE IF EXISTS `#__mokowaas_erp_pipeline_stages`;
|
||||
|
||||
@@ -149,5 +149,42 @@ final class MokoWaaSApi extends CMSPlugin implements SubscriberInterface
|
||||
'erppipeline',
|
||||
['component' => 'com_mokowaas']
|
||||
);
|
||||
|
||||
$router->createCRUDRoutes(
|
||||
'v1/mokowaas/erp/products',
|
||||
'erpproducts',
|
||||
['component' => 'com_mokowaas']
|
||||
);
|
||||
|
||||
$router->createCRUDRoutes(
|
||||
'v1/mokowaas/erp/orders',
|
||||
'erporders',
|
||||
['component' => 'com_mokowaas']
|
||||
);
|
||||
|
||||
$router->createCRUDRoutes(
|
||||
'v1/mokowaas/erp/invoices',
|
||||
'erpinvoices',
|
||||
['component' => 'com_mokowaas']
|
||||
);
|
||||
|
||||
$router->createCRUDRoutes(
|
||||
'v1/mokowaas/erp/payments',
|
||||
'erppayments',
|
||||
['component' => 'com_mokowaas']
|
||||
);
|
||||
|
||||
// E-Signature routes
|
||||
$router->createCRUDRoutes(
|
||||
'v1/mokowaas/erp/esign/requests',
|
||||
'erpsignrequests',
|
||||
['component' => 'com_mokowaas']
|
||||
);
|
||||
|
||||
$router->createCRUDRoutes(
|
||||
'v1/mokowaas/erp/esign/signers',
|
||||
'erpsignsigners',
|
||||
['component' => 'com_mokowaas']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user