diff --git a/assets/pasted-20251211-060813-1bfd24b7.png b/assets/pasted-20251211-060813-1bfd24b7.png new file mode 100644 index 0000000..c686c74 Binary files /dev/null and b/assets/pasted-20251211-060813-1bfd24b7.png differ diff --git a/assets/pasted-20251211-061003-c6ec9aea.png b/assets/pasted-20251211-061003-c6ec9aea.png new file mode 100644 index 0000000..7436ce3 Binary files /dev/null and b/assets/pasted-20251211-061003-c6ec9aea.png differ diff --git a/assets/pasted-20251211-061109-702062e6.png b/assets/pasted-20251211-061109-702062e6.png new file mode 100644 index 0000000..10838fe Binary files /dev/null and b/assets/pasted-20251211-061109-702062e6.png differ diff --git a/assets/pasted-20251211-061208-2fdbda92.png b/assets/pasted-20251211-061208-2fdbda92.png new file mode 100644 index 0000000..192792f Binary files /dev/null and b/assets/pasted-20251211-061208-2fdbda92.png differ diff --git a/assets/pasted-20251211-061245-39ca0406.png b/assets/pasted-20251211-061245-39ca0406.png new file mode 100644 index 0000000..63ebb8e Binary files /dev/null and b/assets/pasted-20251211-061245-39ca0406.png differ diff --git a/assets/pasted-20251211-061329-25a6f76d.png b/assets/pasted-20251211-061329-25a6f76d.png new file mode 100644 index 0000000..5eb2755 Binary files /dev/null and b/assets/pasted-20251211-061329-25a6f76d.png differ diff --git a/auth.php b/auth.php index f0691c7..c97b415 100644 --- a/auth.php +++ b/auth.php @@ -8,7 +8,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { try { $pdo = db(); - $stmt = $pdo->prepare("SELECT u.id, u.username, u.password, r.name as role_name + $stmt = $pdo->prepare("SELECT u.id, u.username, u.password, u.role_id, r.name as role_name FROM users u JOIN roles r ON u.role_id = r.id WHERE u.username = ?"); @@ -20,14 +20,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $stmt = $pdo->prepare("SELECT p.name FROM permissions p JOIN role_permissions rp ON p.id = rp.permission_id - WHERE rp.role_id = (SELECT id FROM roles WHERE name = ?)"); - $stmt->execute([$user['role_name']]); + WHERE rp.role_id = ?"); + $stmt->execute([$user['role_id']]); $permissions = $stmt->fetchAll(PDO::FETCH_COLUMN); $_SESSION['user'] = [ 'id' => $user['id'], 'username' => $user['username'], 'role' => $user['role_name'], + 'role_id' => $user['role_id'], 'permissions' => $permissions ]; unset($_SESSION['error']); diff --git a/db/migrations/010_add_new_approval_roles.sql b/db/migrations/010_add_new_approval_roles.sql new file mode 100644 index 0000000..a2137a1 --- /dev/null +++ b/db/migrations/010_add_new_approval_roles.sql @@ -0,0 +1,6 @@ +INSERT IGNORE INTO `roles` (`name`) VALUES +('Sales Manager'), +('General Manager'), +('Managing Director'), +('Accounts'), +('IT'); diff --git a/db/migrations/012_add_full_application_fields_split.sql b/db/migrations/012_add_full_application_fields_split.sql new file mode 100644 index 0000000..7e23af0 --- /dev/null +++ b/db/migrations/012_add_full_application_fields_split.sql @@ -0,0 +1,52 @@ +-- New fields for customer_applications from Page 1 +ALTER TABLE `customer_applications` ADD COLUMN `fax` VARCHAR(255) DEFAULT NULL; +ALTER TABLE `customer_applications` ADD COLUMN `gst_reg_no` VARCHAR(255) DEFAULT NULL; +ALTER TABLE `customer_applications` ADD COLUMN `company_reg_no` VARCHAR(255) DEFAULT NULL; +ALTER TABLE `customer_applications` ADD COLUMN `date_of_incorporation` DATE DEFAULT NULL; +ALTER TABLE `customer_applications` ADD COLUMN `country_of_incorporation` VARCHAR(255) DEFAULT NULL; +ALTER TABLE `customer_applications` ADD COLUMN `contact_person_designation` VARCHAR(255) DEFAULT NULL; +ALTER TABLE `customer_applications` ADD COLUMN `credit_terms` VARCHAR(255) DEFAULT NULL; +ALTER TABLE `customer_applications` ADD COLUMN `account_setup_ar_statement` BOOLEAN DEFAULT FALSE; +ALTER TABLE `customer_applications` ADD COLUMN `account_setup_dunning_letter` BOOLEAN DEFAULT FALSE; +ALTER TABLE `customer_applications` ADD COLUMN `account_setup_ap_payment` BOOLEAN DEFAULT FALSE; + +-- New table for shareholder/director information from Page 2 +CREATE TABLE IF NOT EXISTS `shareholder_director_information` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `application_id` INT NOT NULL, + `name` VARCHAR(255) DEFAULT NULL, + `address` TEXT DEFAULT NULL, + `perc_of_shareholding` VARCHAR(255) DEFAULT NULL, + `contact_no` VARCHAR(255) DEFAULT NULL, + FOREIGN KEY (`application_id`) REFERENCES `customer_applications`(`id`) ON DELETE CASCADE +); + +-- New fields for customer_trade_references from Page 2 +ALTER TABLE `customer_trade_references` ADD COLUMN `telephone_no` VARCHAR(255) DEFAULT NULL; +ALTER TABLE `customer_trade_references` ADD COLUMN `fax_no` VARCHAR(255) DEFAULT NULL; + +-- New fields for banker's information from Page 3 +ALTER TABLE `customer_bank_details` ADD COLUMN `address` TEXT DEFAULT NULL; +ALTER TABLE `customer_bank_details` ADD COLUMN `swift_code` VARCHAR(255) DEFAULT NULL; +ALTER TABLE `customer_bank_details` ADD COLUMN `contact_person` VARCHAR(255) DEFAULT NULL; +ALTER TABLE `customer_bank_details` ADD COLUMN `telephone_no` VARCHAR(255) DEFAULT NULL; +ALTER TABLE `customer_bank_details` ADD COLUMN `fax_no` VARCHAR(255) DEFAULT NULL; + + +-- New table for financial information from Page 3 +CREATE TABLE IF NOT EXISTS `customer_financial_information` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `customer_application_id` INT NOT NULL, + `latest_audited_financial_year` VARCHAR(255) DEFAULT NULL, + `shareholder_equity` VARCHAR(255) DEFAULT NULL, + `paid_up_capital` VARCHAR(255) DEFAULT NULL, + `annual_turnover` VARCHAR(255) DEFAULT NULL, + `net_profit_loss` VARCHAR(255) DEFAULT NULL, + `currency` VARCHAR(50) DEFAULT NULL, + FOREIGN KEY (`customer_application_id`) REFERENCES `customer_applications`(`id`) ON DELETE CASCADE +); + +-- Declaration and Authorisation from Page 3 +ALTER TABLE `customer_applications` ADD COLUMN `declaration_name` TEXT DEFAULT NULL; +ALTER TABLE `customer_applications` ADD COLUMN `declaration_designation` TEXT DEFAULT NULL; +ALTER TABLE `customer_applications` ADD COLUMN `declaration_date` DATE DEFAULT NULL; diff --git a/db/migrations/013_add_nature_of_business.sql b/db/migrations/013_add_nature_of_business.sql new file mode 100644 index 0000000..dc5b898 --- /dev/null +++ b/db/migrations/013_add_nature_of_business.sql @@ -0,0 +1,7 @@ +ALTER TABLE `customer_applications` MODIFY `company_name` TEXT; +ALTER TABLE `customer_applications` MODIFY `company_website` TEXT; +ALTER TABLE `customer_applications` MODIFY `sales_owner` TEXT; +ALTER TABLE `customer_applications` MODIFY `major_product` TEXT; +ALTER TABLE `customer_applications` MODIFY `credit_rank` TEXT; +ALTER TABLE `customer_applications` MODIFY `del_to_customer_name` TEXT; +ALTER TABLE `customer_applications` ADD COLUMN `nature_of_business` VARCHAR(255) DEFAULT NULL; \ No newline at end of file diff --git a/db/migrations/014_add_credit_terms_requested.sql b/db/migrations/014_add_credit_terms_requested.sql new file mode 100644 index 0000000..f8b6c3a --- /dev/null +++ b/db/migrations/014_add_credit_terms_requested.sql @@ -0,0 +1 @@ +ALTER TABLE `customer_applications` ADD COLUMN `credit_terms_requested` VARCHAR(255) DEFAULT NULL; \ No newline at end of file diff --git a/db/migrations/015_add_credit_limit_requested.sql b/db/migrations/015_add_credit_limit_requested.sql new file mode 100644 index 0000000..0106f79 --- /dev/null +++ b/db/migrations/015_add_credit_limit_requested.sql @@ -0,0 +1 @@ +ALTER TABLE `customer_applications` ADD COLUMN `credit_limit_requested` DECIMAL(15, 2) DEFAULT NULL; \ No newline at end of file diff --git a/db/migrations/016_add_nric_to_shareholders.sql b/db/migrations/016_add_nric_to_shareholders.sql new file mode 100644 index 0000000..5557e7a --- /dev/null +++ b/db/migrations/016_add_nric_to_shareholders.sql @@ -0,0 +1 @@ +ALTER TABLE `shareholder_director_information` ADD COLUMN `nric_fin` VARCHAR(255) DEFAULT NULL; \ No newline at end of file diff --git a/db/migrations/017_create_customer_principals_table.sql b/db/migrations/017_create_customer_principals_table.sql new file mode 100644 index 0000000..b28e26c --- /dev/null +++ b/db/migrations/017_create_customer_principals_table.sql @@ -0,0 +1,10 @@ +-- Create customer_principals table +CREATE TABLE IF NOT EXISTS `customer_principals` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `customer_application_id` INT NOT NULL, + `name` VARCHAR(255) NOT NULL, + `designation` VARCHAR(255) NOT NULL, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + FOREIGN KEY (`customer_application_id`) REFERENCES `customer_applications`(`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/includes/auth_helpers.php b/includes/auth_helpers.php index 4fda5fc..bef1259 100644 --- a/includes/auth_helpers.php +++ b/includes/auth_helpers.php @@ -7,6 +7,13 @@ function hasPermission($permission_name) { return false; } +function get_user_role_id() { + if (isset($_SESSION['user']['role_id'])) { + return $_SESSION['user']['role_id']; + } + return null; +} + function redirect_if_not_authenticated() { if (!isset($_SESSION['user'])) { header('Location: login.php'); diff --git a/manage_users.php b/manage_users.php index bbc752b..e764bbe 100644 --- a/manage_users.php +++ b/manage_users.php @@ -3,183 +3,262 @@ session_start(); require_once 'includes/auth_helpers.php'; require_once 'db/config.php'; -// Protect route: check if user is logged in and has permission redirect_if_not_authenticated(); redirect_if_no_permission('manage_users'); +$pdo = db(); $user = $_SESSION['user']; -// Dynamic project data from environment -$projectName = $_SERVER['PROJECT_NAME'] ?? 'Customer Master'; -$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Customer Master Registration & Maintenance'; -$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; +// Handle POST requests for Create, Update, Delete +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $action = $_POST['action'] ?? ''; -// Handle file upload -if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['userCsv'])) { - $file = $_FILES['userCsv']; + try { + if ($action === 'create_user') { + $username = $_POST['username']; + $password = $_POST['password']; + $role_id = $_POST['role_id']; + $hashed_password = password_hash($password, PASSWORD_DEFAULT); - if ($file['error'] === UPLOAD_ERR_OK) { - $csvData = array_map('str_getcsv', file($file['tmp_name'])); - $header = array_shift($csvData); - $expectedHeader = ['username', 'password', 'role']; - - if ($header === $expectedHeader) { - $pdo = db(); - $pdo->beginTransaction(); - $createdCount = 0; - $errorCount = 0; - $errors = []; - - // Get all roles from the database - $stmt = $pdo->query("SELECT id, name FROM roles"); - $roles = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); - - foreach ($csvData as $rowIndex => $row) { - $username = $row[0] ?? null; - $password = $row[1] ?? null; - $roleName = $row[2] ?? null; - - if (empty($username) || empty($password) || empty($roleName)) { - $errorCount++; - $errors[] = "Row " . ($rowIndex + 2) . ": Invalid data."; - continue; - } - - if (!in_array($roleName, $roles)) { - $errorCount++; - $errors[] = "Row " . ($rowIndex + 2) . ": Role '".htmlspecialchars($roleName)."' does not exist."; - continue; - } - - $roleId = array_search($roleName, $roles); - - try { - $stmt = $pdo->prepare("SELECT id FROM users WHERE username = ?"); - $stmt->execute([$username]); - if ($stmt->fetch()) { - $errorCount++; - $errors[] = "Row " . ($rowIndex + 2) . ": User '".htmlspecialchars($username)."' already exists."; - continue; - } - - $hashedPassword = password_hash($password, PASSWORD_DEFAULT); - $stmt = $pdo->prepare("INSERT INTO users (username, password, role_id) VALUES (?, ?, ?)"); - $stmt->execute([$username, $hashedPassword, $roleId]); - $createdCount++; - } catch (PDOException $e) { - $errorCount++; - $errors[] = "Row " . ($rowIndex + 2) . ": Database error."; - } - } - - if ($errorCount > 0) { - $pdo->rollBack(); - $_SESSION['flash_message'] = [ - 'type' => 'danger', - 'message' => "User import failed with {$errorCount} errors.", - 'errors' => $errors - ]; - } else { - $pdo->commit(); - $_SESSION['flash_message'] = [ - 'type' => 'success', - 'message' => "Successfully created {$createdCount} users." - ]; - } - } else { - $_SESSION['flash_message'] = [ - 'type' => 'danger', - 'message' => 'Invalid CSV header. Expected: username,password,role' - ]; + $stmt = $pdo->prepare("INSERT INTO users (username, password, role_id) VALUES (?, ?, ?)"); + $stmt->execute([$username, $hashed_password, $role_id]); + $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'User created successfully.']; } - } else { - $_SESSION['flash_message'] = [ - 'type' => 'danger', - 'message' => 'Error uploading file.' - ]; + + if ($action === 'update_role') { + $user_id = $_POST['user_id']; + $role_id = $_POST['role_id']; + + $stmt = $pdo->prepare("UPDATE users SET role_id = ? WHERE id = ?"); + $stmt->execute([$role_id, $user_id]); + $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'User role updated successfully.']; + } + + if ($action === 'delete_user') { + $user_id = $_POST['user_id']; + + // Prevent admin from deleting themselves + if ($user_id == get_user_id()) { + $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'You cannot delete your own account.']; + } else { + $stmt = $pdo->prepare("DELETE FROM users WHERE id = ?"); + $stmt->execute([$user_id]); + $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'User deleted successfully.']; + } + } + } catch (PDOException $e) { + $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'Database error: ' . $e->getMessage()]; } + header('Location: manage_users.php'); exit(); } + +// Fetch all users and roles +$stmt_users = $pdo->query("SELECT u.id, u.username, r.name as role_name, u.created_at FROM users u JOIN roles r ON u.role_id = r.id ORDER BY u.created_at DESC"); +$users_list = $stmt_users->fetchAll(); + +$stmt_roles = $pdo->query("SELECT id, name FROM roles ORDER BY name"); +$roles = $stmt_roles->fetchAll(); + ?> - Manage Users - <?php echo htmlspecialchars($projectName); ?> + Manage Users
-
+ + + + + + + + + + - + \ No newline at end of file diff --git a/new_application.php b/new_application.php index 16f9cb7..b794962 100644 --- a/new_application.php +++ b/new_application.php @@ -13,11 +13,15 @@ redirect_if_no_permission('create_application'); @@ -25,756 +29,433 @@ redirect_if_no_permission('create_application');

New Customer Application

+ + + + + +
- -
+ + +
-
Company Details
+
PAGE 1 of 6: CUSTOMER INFORMATION
-
+
-
- - -
+
+
+ +
-
- +
+
-
- - -
-
-
-
- - -
-
- - -
-
-
- - -
-
-
-
- - -
-
-
Financial & Credit Details
-
-
-
- - -
-
- -
- - -
-
-
-
-
- - -
-
- - -
-
-
-
- - -
-
-
-
Customer's P/L Information
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
ROHM Sales Target (KUS$)
-
- - + +
-
- - -
-
- - -
-
-
-
Credit Information
-
-
- - -
-
- - -
-
-
-
Credit Research
-
-
- - -
-
- - -
-
-
-
-
- - -
-
- - -
-
-
-
-
- - -
-
-
Del-To Informations
-
-
-
- - -
-
- - -
-
-
- - -
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
-
-
- -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- - -
-
-
-
-
- - -
-
-
SOP
-
-
-
-
Document Requirements
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
Packing Requirements
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
-
Forwarder Information
-
-
- - -
-
- - -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
- - -
-
-
-
Special Instructions
-
-
- - -
-
- - -
-
- - + +
- - + +
- - + + +
+
+
+
+ + +
+
+ +
- - -
-
-
-
- - -
-
-
- Contacts - -
-
- -
-
- - + +
+
+
+
+
-
-
-
-
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
ACCOUNT SET UP FOR
+
+
+
+
+
+ +
DELIVERY TO
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ +
-
- - -
-
-
- Addresses - -
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
+
+
- -
-
+ +
+
- Trade References - + PAGE 2 of 6: PARTICULARS OF SHAREHOLDER'S / DIRECTOR'S + +
+
+ +
+
+
+ + +
+
+ + +
+
+
+ PAGE 3 of 6: TRADE REFERENCES +
- -
-
-
-
-
-
-
-
-
-
-
+
+
+ + +
- -
+ +
-
Bank Details
+
PAGE 4 of 6: BANKER'S INFORMATION
+
+ + +
+
+ + +
- - + +
- - + +
- - + +
- - + +
- - + +
+
+ + +
- -
+ +
-
Declaration
+
PAGE 5 of 6: FINANCIAL / CREDIT INFORMATION
-
- - -
-
- -
- +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ +
- -
+
+ + +
-
- - - + +
+
+
PAGE 6 of 6: DECLARATION AND AUTHORISATION
+
+

We, the undersigned, hereby apply for credit facility with your company and we declare that the information given above and in any attached documents is true and correct. We authorise you or your representative to obtain any further information you may require from our banker(s) or other sources to determine our credit worthiness and we agree to abide by your standard terms and conditions of sales.

+

We futher undertake to inform you in writing of any changes in our shareholding / directorship / management and registered particulars, and we agree that we are liable for all debts incurred until such notice is received by you.

+

In the event that the credit application is not approved, we understand that you are not obliged to assign any reason for the decision.

+ +
+
+ + +
+
+ + +
+
+
+
+ +
+ + Signature area +
+ +
+
+ + +
+
+
+
+
+ + +
- - \ No newline at end of file + diff --git a/process_approval.php b/process_approval.php index f16dd1b..9e84d48 100644 --- a/process_approval.php +++ b/process_approval.php @@ -13,6 +13,7 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') { $application_id = $_POST['application_id'] ?? null; $action = $_POST['action'] ?? null; +$comments = $_POST['comments'] ?? ''; if (!$application_id || !$action) { header('Location: view_applications.php'); @@ -21,9 +22,17 @@ if (!$application_id || !$action) { $pdo = db(); +// --- New Approval Workflow --- +$approval_levels = [ + 1 => 'Sales Manager', + 2 => 'General Manager', + 3 => 'Managing Director' +]; +// --- End New Approval Workflow --- + // Helper function to get user emails by role name function get_user_emails_by_role($role_name, $pdo) { - $stmt = $pdo->prepare('SELECT u.email FROM users u JOIN user_roles ur ON u.id = ur.user_id JOIN roles r ON ur.role_id = r.id WHERE r.name = ?'); + $stmt = $pdo->prepare('SELECT email FROM users u JOIN roles r ON u.role_id = r.id WHERE r.name = ?'); $stmt->execute([$role_name]); return $stmt->fetchAll(PDO::FETCH_COLUMN); } @@ -37,93 +46,127 @@ if (!$application) { die('Application not found.'); } -// Check permission -$approval_level = $application['approval_level']; -$permission_needed = 'approve_level_' . $approval_level; -if (!hasPermission($permission_needed)) { - $_SESSION['flash_message'] = [ - 'type' => 'danger', - 'message' => 'You do not have permission to perform this action.' - ]; - header('Location: view_application.php?id=' . $application_id); - exit(); -} - // Get applicant email $stmt_applicant = $pdo->prepare('SELECT email FROM customer_contacts WHERE customer_application_id = ? AND is_primary = 1'); $stmt_applicant->execute([$application_id]); $applicant_email = $stmt_applicant->fetchColumn(); +// Get current user's role +$current_user_role_id = get_user_role_id(); +$stmt_role = $pdo->prepare("SELECT name FROM roles WHERE id = ?"); +$stmt_role->execute([$current_user_role_id]); +$current_user_role_name = $stmt_role->fetchColumn(); + +$current_level = $application['approval_level']; +$required_role = $approval_levels[$current_level] ?? null; + +// Check if the current user has the required role for this level +if ($current_user_role_name !== $required_role && $current_user_role_name !== 'admin') { + $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'You do not have permission to perform this action.']; + header('Location: view_application.php?id=' . $application_id); + exit(); +} + + try { + $pdo->beginTransaction(); + + // Log the action + $stmt_log = $pdo->prepare("INSERT INTO application_approvals (application_id, approver_id, approval_level, status, comments) VALUES (?, ?, ?, ?, ?)"); + $stmt_log->execute([$application_id, get_user_id(), $current_level, ucfirst($action), $comments]); + if ($action === 'approve') { - $next_approval_level = $approval_level + 1; - $next_approver_role_name = 'Approver Level ' . $next_approval_level; - - $stmt_role = $pdo->prepare("SELECT id FROM roles WHERE name = ?"); - $stmt_role->execute([$next_approver_role_name]); - $next_approver_role = $stmt_role->fetch(); + $next_level = $current_level + 1; - if ($next_approver_role) { + if (array_key_exists($next_level, $approval_levels)) { // Move to next approval level - $stmt = $pdo->prepare('UPDATE customer_applications SET approval_level = ?, current_approver_role_id = ? WHERE id = ?'); - $stmt->execute([$next_approval_level, $next_approver_role['id'], $application_id]); - $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'Application approved and moved to the next level.']; + $next_role_name = $approval_levels[$next_level]; + $stmt_next_role = $pdo->prepare("SELECT id FROM roles WHERE name = ?"); + $stmt_next_role->execute([$next_role_name]); + $next_role_id = $stmt_next_role->fetchColumn(); + $stmt_update = $pdo->prepare('UPDATE customer_applications SET approval_level = ?, current_approver_role_id = ?, status = \'Pending\' WHERE id = ?'); + $stmt_update->execute([$next_level, $next_role_id, $application_id]); + + $_SESSION['flash_message'] = ['type' => 'success', 'message' => "Application approved and sent to {$next_role_name}."]; + + /* // Notify next approvers - $next_approver_emails = get_user_emails_by_role($next_approver_role_name, $pdo); + $next_approver_emails = get_user_emails_by_role($next_role_name, $pdo); if (!empty($next_approver_emails)) { - // Get Sales Rep name - $stmt_sales_rep = $pdo->prepare('SELECT name FROM users WHERE id = ?'); - $stmt_sales_rep->execute([$application['created_by_user_id']]); - $sales_rep_name = $stmt_sales_rep->fetchColumn(); - - // Get Credit Amount - $stmt_credit = $pdo->prepare('SELECT requested_credit_limit FROM financial_credit_details WHERE customer_application_id = ?'); - $stmt_credit->execute([$application_id]); - $credit_amount = $stmt_credit->fetchColumn(); - - $subject = 'Credit Application - ' . $application['company_name']; - $submission_date = date('Y-m-d'); - $body = " -

A new credit application requires your approval.

-

Customer Name: {$application['company_name']}

-

Sales Rep: {$sales_rep_name}

-

Credit Amount: $" . number_format($credit_amount, 2) . "

-

Submission Date: {$submission_date}

-

View Application

- "; + $subject = "Application requires your approval: " . $application['company_name']; + $body = "

A credit application for {$application['company_name']} requires your review.

View Application

"; MailService::sendMail($next_approver_emails, $subject, $body); } + */ } else { // Final approval - $stmt = $pdo->prepare("UPDATE customer_applications SET status = 'APPROVED', approval_level = NULL, current_approver_role_id = NULL WHERE id = ?"); - $stmt->execute([$application_id]); - $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'Application approved.']; - + $stmt_update = $pdo->prepare("UPDATE customer_applications SET status = 'Approved', approval_level = NULL, current_approver_role_id = NULL WHERE id = ?"); + $stmt_update->execute([$application_id]); + $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'Application has been fully approved.']; + + /* // Notify applicant if ($applicant_email) { $subject = 'Your Application has been Approved: ' . $application['application_id']; $body = "

Congratulations! Your customer application ({$application['application_id']}) has been approved.

"; MailService::sendMail($applicant_email, $subject, $body); } + */ } - } elseif ($action === 'reject') { - $stmt = $pdo->prepare("UPDATE customer_applications SET status = 'REJECTED' WHERE id = ?"); - $stmt->execute([$application_id]); - $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'Application rejected.']; + } elseif ($action === 'return') { + $prev_level = $current_level - 1; + + if (array_key_exists($prev_level, $approval_levels)) { + // Return to previous approval level + $prev_role_name = $approval_levels[$prev_level]; + $stmt_prev_role = $pdo->prepare("SELECT id FROM roles WHERE name = ?"); + $stmt_prev_role->execute([$prev_role_name]); + $prev_role_id = $stmt_prev_role->fetchColumn(); + + $stmt_update = $pdo->prepare('UPDATE customer_applications SET approval_level = ?, current_approver_role_id = ?, status = \'Returned\' WHERE id = ?'); + $stmt_update->execute([$prev_level, $prev_role_id, $application_id]); + + $_SESSION['flash_message'] = ['type' => 'warning', 'message' => "Application returned to {$prev_role_name} for review."]; + + /* + // Notify previous approvers + $prev_approver_emails = get_user_emails_by_role($prev_role_name, $pdo); + if (!empty($prev_approver_emails)) { + $subject = "Application returned for your review: " . $application['company_name']; + $body = "

The application for {$application['company_name']} has been returned for your review with the following comments:

" . htmlspecialchars($comments) . "

View Application

"; + MailService::sendMail($prev_approver_emails, $subject, $body); + } + */ + } else { + // Cannot return from the first level, this case should ideally be handled in the UI + $_SESSION['flash_message'] = ['type' => 'danger', 'message' => "Cannot return the application from the first approval level."]; + } + + } elseif ($action === 'reject') { + $stmt_update = $pdo->prepare("UPDATE customer_applications SET status = 'Rejected' WHERE id = ?"); + $stmt_update->execute([$application_id]); + + $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'Application has been rejected.']; + + /* // Notify applicant if ($applicant_email) { $subject = 'Your Application has been Rejected: ' . $application['application_id']; - $body = "

We regret to inform you that your customer application ({$application['application_id']}) has been rejected.

"; + $body = "

We regret to inform you that your customer application ({$application['application_id']}) has been rejected. The following comments were provided:

" . htmlspecialchars($comments) . "

"; MailService::sendMail($applicant_email, $subject, $body); } + */ } -} catch (PDOException $e) { + $pdo->commit(); + +} catch (Exception $e) { + $pdo->rollBack(); error_log('Approval processing failed: ' . $e->getMessage()); - $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'An error occurred. Please try again.']; + $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'An error occurred while processing the application. Please try again.']; } header('Location: view_application.php?id=' . $application_id); -exit(); +exit(); \ No newline at end of file diff --git a/submit_application.php b/submit_application.php index f87be1d..f1b9f4b 100644 --- a/submit_application.php +++ b/submit_application.php @@ -1,6 +1,7 @@ prepare("SELECT id FROM roles WHERE name = 'Approver Level 1'"); + $pdo->beginTransaction(); + + // 1. Insert into customer_applications + $stmt = $pdo->prepare( + 'INSERT INTO customer_applications ( + application_id, customer_id, created_by, company_name, company_phone, fax, gst_reg_no, + company_reg_no, date_of_incorporation, country_of_incorporation, nature_of_business, + credit_terms_requested, credit_limit_requested, account_setup_ar_statement, + account_setup_dunning_letter, account_setup_ap_payment, + declaration_name, declaration_designation, declaration_date + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' + ); + $stmt->execute([ + uniqid(), + $_SESSION['user']['id'], + $_SESSION['user']['id'], + $_POST['company_name'] ?? null, + $_POST['company_phone'] ?? null, + $_POST['fax'] ?? null, + $_POST['gst_reg_no'] ?? null, + $_POST['company_reg_no'] ?? null, + $_POST['date_of_incorporation'] ?? null, + $_POST['country_of_incorporation'] ?? null, + $_POST['nature_of_business'] ?? null, + $_POST['credit_terms_requested'] ?? null, + $_POST['credit_limit_requested'] ?? null, + isset($_POST['account_setup_ar_statement']) ? 1 : 0, + isset($_POST['account_setup_dunning_letter']) ? 1 : 0, + isset($_POST['account_setup_ap_payment']) ? 1 : 0, + $_POST['declaration_name'] ?? null, + $_POST['declaration_designation'] ?? null, + $_POST['declaration_date'] ?? null + ]); + $customer_application_id = $pdo->lastInsertId(); + + // Insert Primary Contact + if (!empty($_POST['contact_person_name']) && !empty($_POST['contact_person_email'])) { + $stmt_contact = $pdo->prepare( + 'INSERT INTO customer_contacts (customer_application_id, name, email, phone, is_primary) VALUES (?, ?, ?, ?, ?)' + ); + $stmt_contact->execute([ + $customer_application_id, + $_POST['contact_person_name'], + $_POST['contact_person_email'], + $_POST['contact_person_phone'] ?? null, + 1 // Set as primary contact + ]); + } + + // Insert Billing Address + if (!empty($_POST['company_address'])) { + $stmt_address = $pdo->prepare( + 'INSERT INTO customer_addresses (customer_application_id, address_type, address_line_1) VALUES (?, ?, ?)' + ); + $stmt_address->execute([$customer_application_id, 'BILLING', $_POST['company_address']]); + } + + // Insert Delivery Address + if (!empty($_POST['del_to_address'])) { + $stmt_del_address = $pdo->prepare( + 'INSERT INTO customer_addresses (customer_application_id, address_type, address_line_1) VALUES (?, ?, ?)' + ); + $stmt_del_address->execute([$customer_application_id, 'SHIPPING', $_POST['del_to_address']]); + } + + // 2. Insert into shareholder_director_information + if (isset($_POST['shareholder']) && is_array($_POST['shareholder'])) { + $stmt_shareholder = $pdo->prepare( + 'INSERT INTO shareholder_director_information (application_id, name, address, nric_fin, perc_of_shareholding, contact_no) VALUES (?, ?, ?, ?, ?, ?)' + ); + foreach ($_POST['shareholder'] as $shareholder) { + if (empty($shareholder['name'])) continue; // Skip empty rows + $stmt_shareholder->execute([ + $customer_application_id, + $shareholder['name'] ?? null, + $shareholder['address'] ?? null, + $shareholder['nric_fin'] ?? null, + $shareholder['perc_of_shareholding'] ?? null, + $shareholder['contact_no'] ?? null + ]); + } + } + + // 3. Insert into customer_trade_references + if (isset($_POST['trade_reference']) && is_array($_POST['trade_reference'])) { + $stmt_trade_ref = $pdo->prepare( + 'INSERT INTO customer_trade_references (customer_application_id, company_name, contact_person, telephone_no, fax_no) VALUES (?, ?, ?, ?, ?)' + ); + foreach ($_POST['trade_reference'] as $trade_ref) { + if (empty($trade_ref['company_name'])) continue; // Skip empty rows + $stmt_trade_ref->execute([ + $customer_application_id, + $trade_ref['company_name'] ?? null, + $trade_ref['contact_person'] ?? null, + $trade_ref['telephone_no'] ?? null, + $trade_ref['fax_no'] ?? null + ]); + } + } + + // 4. Insert into customer_bank_details + if (!empty($_POST['bank_name'])) { + $stmt_bank = $pdo->prepare( + 'INSERT INTO customer_bank_details (customer_application_id, bank_name, address, swift_code, account_number, contact_person, telephone_no, fax_no) VALUES (?, ?, ?, ?, ?, ?, ?, ?)' + ); + $stmt_bank->execute([ + $customer_application_id, + $_POST['bank_name'] ?? null, + $_POST['bank_address'] ?? null, + $_POST['bank_swift_code'] ?? null, + $_POST['bank_account_no'] ?? null, + $_POST['bank_contact_person'] ?? null, + $_POST['bank_telephone_no'] ?? null, + $_POST['bank_fax_no'] ?? null + ]); + } + + // 5. Insert into customer_financial_information + if (!empty($_POST['paid_up_capital'])) { + $stmt_financial = $pdo->prepare( + 'INSERT INTO customer_financial_information (customer_application_id, latest_audited_financial_year, shareholder_equity, paid_up_capital, annual_turnover, net_profit_loss, currency) VALUES (?, ?, ?, ?, ?, ?, ?)' + ); + $stmt_financial->execute([ + $customer_application_id, + $_POST['latest_audited_financial_year'] ?? null, + $_POST['shareholder_equity'] ?? null, + $_POST['paid_up_capital'] ?? null, + $_POST['annual_turnover'] ?? null, + $_POST['net_profit_loss'] ?? null, + $_POST['currency'] ?? null + ]); + } + + // Set initial approval status + $stmt_role = $pdo->prepare("SELECT id FROM roles WHERE name = 'Sales Manager'"); $stmt_role->execute(); $approver_role = $stmt_role->fetch(PDO::FETCH_ASSOC); $approver_role_id = $approver_role ? $approver_role['id'] : null; - $pdo->beginTransaction(); - - // 1. Insert into customer_applications - $application_id = 'APP-' . strtoupper(uniqid()); - $created_by = $_SESSION['user']['username'] ?? 'system'; - - $stmt = $pdo->prepare( - 'INSERT INTO customer_applications (user_id, company_name, company_website, company_phone, sales_owner, payment_terms, tags, notes, declaration_text, signature_path, major_product, capital, capital_currency, main_shareholders, num_employees, payment_terms_ar, pl_year, net_sales, net_income_margin, net_income_margin_ratio, sales_target_this_year, sales_target_next_year, sales_target_after_next, credit_rank, credit_limit, credit_research_status, credit_research_reason, tax_rate_area, billing_type, del_to_code, delivery_abbreviation, del_to_customer_name, del_to_address_1, del_to_address_2, del_to_address_3, del_to_address_4, del_to_postcode, del_to_phone, del_to_area_code, del_to_transportation_code, del_to_stock_point_code, del_to_recipient_section, del_to_country_code, del_to_shipment_flag, del_to_transport_days, del_to_shipment_condition_category, del_to_transport_service_exist, del_to_shipment_condition_place, doc_req_do, doc_req_packing_list, doc_req_invoice, doc_req_export_permit, doc_req_po_do_inv, doc_req_do_inv, doc_req_others, pack_req_one_line_carton, pack_req_one_item_carton, pack_req_one_item_pocket, pack_req_thomson_label, pack_req_contents_label, pack_req_delivery_schedule, forwarder_name, forwarder_code, forwarder_address, forwarder_contact_person, forwarder_phone, forwarder_fax, forwarder_delivery_method, forwarder_delivery_timings, forwarder_delivery_requirements, special_instructions_shipping_mark, special_instructions_fax_documents, special_instructions_details, special_instructions_attention_to, special_instructions_fax_number, remarks) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' - ); - $stmt->execute([ - $_SESSION['user_id'], - $_POST['company_name'], - $_POST['company_website'], - $_POST['company_phone'], - $_POST['sales_owner'], - $_POST['payment_terms'], - $_POST['tags'], - $_POST['notes'], - $_POST['declaration_text'], - $signature_path, - $_POST['major_product'] ?? null, - $_POST['capital'] ?? null, - $_POST['capital_currency'] ?? null, - $_POST['main_shareholders'] ?? null, - $_POST['num_employees'] ?? null, - $_POST['payment_terms_ar'] ?? null, - $_POST['pl_year'] ?? null, - $_POST['net_sales'] ?? null, - $_POST['net_income_margin'] ?? null, - $_POST['net_income_margin_ratio'] ?? null, - $_POST['sales_target_this_year'] ?? null, - $_POST['sales_target_next_year'] ?? null, - $_POST['sales_target_after_next'] ?? null, - $_POST['credit_rank'] ?? null, - $_POST['credit_limit'] ?? null, - $_POST['credit_research_status'] ?? null, - $_POST['credit_research_reason'] ?? null, - $_POST['tax_rate_area'] ?? null, - $_POST['billing_type'] ?? null, - $_POST['del_to_code'] ?? null, - $_POST['delivery_abbreviation'] ?? null, - $_POST['del_to_customer_name'] ?? null, - $_POST['del_to_address_1'] ?? null, - $_POST['del_to_address_2'] ?? null, - $_POST['del_to_address_3'] ?? null, - $_POST['del_to_address_4'] ?? null, - $_POST['del_to_postcode'] ?? null, - $_POST['del_to_phone'] ?? null, - $_POST['del_to_area_code'] ?? null, - $_POST['del_to_transportation_code'] ?? null, - $_POST['del_to_stock_point_code'] ?? null, - $_POST['del_to_recipient_section'] ?? null, - $_POST['del_to_country_code'] ?? null, - $_POST['del_to_shipment_flag'] ?? null, - $_POST['del_to_transport_days'] ?? null, - $_POST['del_to_shipment_condition_category'] ?? null, - isset($_POST['del_to_transport_service_exist']) ? implode(',', $_POST['del_to_transport_service_exist']) : null, - $_POST['del_to_shipment_condition_place'] ?? null, - $_POST['doc_req_do'] ?? null, - $_POST['doc_req_packing_list'] ?? null, - $_POST['doc_req_invoice'] ?? null, - $_POST['doc_req_export_permit'] ?? null, - $_POST['doc_req_po_do_inv'] ?? null, - $_POST['doc_req_do_inv'] ?? null, - $_POST['doc_req_others'] ?? null, - $_POST['pack_req_one_line_carton'] ?? null, - $_POST['pack_req_one_item_carton'] ?? null, - $_POST['pack_req_one_item_pocket'] ?? null, - $_POST['pack_req_thomson_label'] ?? null, - $_POST['pack_req_contents_label'] ?? null, - $_POST['pack_req_delivery_schedule'] ?? null, - $_POST['forwarder_name'] ?? null, - $_POST['forwarder_code'] ?? null, - $_POST['forwarder_address'] ?? null, - $_POST['forwarder_contact_person'] ?? null, - $_POST['forwarder_phone'] ?? null, - $_POST['forwarder_fax'] ?? null, - $_POST['forwarder_delivery_method'] ?? null, - $_POST['forwarder_delivery_timings'] ?? null, - $_POST['forwarder_delivery_requirements'] ?? null, - $_POST['special_instructions_shipping_mark'] ?? null, - $_POST['special_instructions_fax_documents'] ?? null, - $_POST['special_instructions_details'] ?? null, - $_POST['special_instructions_attention_to'] ?? null, - $_POST['special_instructions_fax_number'] ?? null, - $_POST['remarks'] ?? null - ]); - $customer_application_id = $pdo->lastInsertId(); - - // 2. Insert into customer_contacts - if (isset($_POST['contact']) && is_array($_POST['contact'])) { - $stmt_contact = $pdo->prepare( - 'INSERT INTO customer_contacts (customer_application_id, name, email, phone, is_primary) VALUES (?, ?, ?, ?, ?)' - ); - foreach ($_POST['contact'] as $index => $contact) { - $is_primary = (isset($contact['is_primary']) && $contact['is_primary'] == '1'); - $stmt_contact->execute([ - $customer_application_id, - $contact['name'], - $contact['email'], - $contact['phone'], - $is_primary ? 1 : 0 - ]); - } - } - - // 3. Insert into customer_addresses - if (isset($_POST['address']) && is_array($_POST['address'])) { - $stmt_address = $pdo->prepare( - 'INSERT INTO customer_addresses (customer_application_id, address_type, address_line_1, address_line_2, city, state, postal_code, country) VALUES (?, ?, ?, ?, ?, ?, ?, ?)' - ); - foreach ($_POST['address'] as $address) { - $stmt_address->execute([ - $customer_application_id, - $address['type'], - $address['line1'], - $address['line2'], - $address['city'], - $address['state'], - $address['postal_code'], - $address['country'] - ]); - } - } - - // 4. Insert into customer_trade_references - if (isset($_POST['trade_reference']) && is_array($_POST['trade_reference'])) { - $stmt_trade_ref = $pdo->prepare( - 'INSERT INTO customer_trade_references (customer_application_id, company_name, contact_person, email, phone, address) VALUES (?, ?, ?, ?, ?, ?)' - ); - foreach ($_POST['trade_reference'] as $trade_ref) { - $stmt_trade_ref->execute([ - $customer_application_id, - $trade_ref['company_name'], - $trade_ref['contact_person'], - $trade_ref['email'], - $trade_ref['phone'], - $trade_ref['address'] - ]); - } - } - - // 5. Insert into customer_bank_details - if (isset($_POST['bank_name'])) { - $stmt_bank = $pdo->prepare( - 'INSERT INTO customer_bank_details (customer_application_id, bank_name, branch, bsb_number, account_number, account_name) VALUES (?, ?, ?, ?, ?, ?)' - ); - $stmt_bank->execute([ - $customer_application_id, - $_POST['bank_name'], - $_POST['branch'], - $_POST['bsb_number'], - $_POST['account_number'], - $_POST['account_name'] - ]); - } - - // 6. Handle Signature and Declaration - $signature_path = null; - if (isset($_POST['signature']) && !empty($_POST['signature'])) { - $signature_data = $_POST['signature']; - list($type, $data) = explode(';', $signature_data); - list(, $data) = explode(',', $data); - $data = base64_decode($data); - $signature_filename = 'signature_' . $application_id . '_' . time() . '.png'; - $signature_path = 'uploads/' . $signature_filename; - file_put_contents($signature_path, $data); - } - - $stmt_declar = $pdo->prepare('UPDATE customer_applications SET declaration_text = ?, signature_path = ? WHERE id = ?'); - $stmt_declar->execute([ - $_POST['declaration_text'], - $signature_path, - $customer_application_id - ]); + $stmt_update = $pdo->prepare('UPDATE customer_applications SET approval_level = 1, current_approver_role_id = ? WHERE id = ?'); + $stmt_update->execute([$approver_role_id, $customer_application_id]); $pdo->commit(); - // Notify approvers - require_once 'mail/MailService.php'; - $approver_emails = get_user_emails_by_role('Approver Level 1', $pdo); - if (!empty($approver_emails)) { - // Get Sales Rep name - $stmt_sales_rep = $pdo->prepare('SELECT name FROM users WHERE id = ?'); - $stmt_sales_rep->execute([$_SESSION['user_id']]); - $sales_rep_name = $stmt_sales_rep->fetchColumn(); - - $subject = 'New Credit Application Submitted - ' . $_POST['company_name']; - $submission_date = date('Y-m-d'); - $body = " -

A new credit application has been submitted and requires your approval.

-

Customer Name: {$_POST['company_name']}

-

Sales Rep: {$sales_rep_name}

-

Credit Amount: $" . number_format($_POST['credit_limit'], 2) . "

-

Submission Date: {$submission_date}

-

View Application

- "; - MailService::sendMail($approver_emails, $subject, $body); - } - - // Redirect to dashboard with success message $_SESSION['flash_message'] = [ 'type' => 'success', - 'message' => 'Customer application (' . $application_id . ') submitted successfully!' + 'message' => 'Customer application submitted successfully!' ]; header('Location: index.php'); exit(); -function get_user_emails_by_role($role_name, $pdo) { - $stmt = $pdo->prepare('SELECT u.email FROM users u JOIN user_roles ur ON u.id = ur.user_id JOIN roles r ON ur.role_id = r.id WHERE r.name = ?'); - $stmt->execute([$role_name]); - return $stmt->fetchAll(PDO::FETCH_COLUMN); -} - } catch (PDOException $e) { $pdo->rollBack(); error_log('Application submission failed: ' . $e->getMessage()); - // Redirect back to form with error message $_SESSION['flash_message'] = [ 'type' => 'danger', - 'message' => 'There was an error submitting your application. Please try again. ' . $e->getMessage() + 'message' => 'There was an error submitting your application. Please check the data and try again. Error: ' . $e->getMessage() ]; header('Location: new_application.php'); exit(); diff --git a/submit_for_approval.php b/submit_for_approval.php new file mode 100644 index 0000000..ad4b4f0 --- /dev/null +++ b/submit_for_approval.php @@ -0,0 +1,69 @@ +prepare("SELECT id FROM roles WHERE name = 'Sales Manager'"); +$stmt_role->execute(); +$sales_manager_role_id = $stmt_role->fetchColumn(); + +if (!$sales_manager_role_id) { + $_SESSION['flash_message'] = [ + 'type' => 'danger', + 'message' => 'Error: Sales Manager role not found. Cannot submit for approval.' + ]; + header('Location: view_application.php?id=' . $application_id); + exit(); +} + +// Update the application to start the approval process +$stmt = $pdo->prepare( + 'UPDATE customer_applications + SET status = ?, approval_level = ?, current_approver_role_id = ? + WHERE id = ? AND status = ?' +); + +$success = $stmt->execute([ + 'Pending', + 1, // Start at level 1 + $sales_manager_role_id, + $application_id, + 'Draft' // Ensure we only update drafts +]); + +if ($success && $stmt->rowCount() > 0) { + // Create initial approval history entry + $stmt_history = $pdo->prepare( + 'INSERT INTO application_approvals (application_id, approver_id, status, comments, created_at) VALUES (?, ?, ?, ?, NOW())' + ); + $stmt_history->execute([ + $application_id, + get_user_id(), // The user submitting the application + 'Submitted', + 'Application submitted for approval.' + ]); + + $_SESSION['flash_message'] = [ + 'type' => 'success', + 'message' => 'Application successfully submitted for approval.' + ]; +} else { + $_SESSION['flash_message'] = [ + 'type' => 'danger', + 'message' => 'Failed to submit application. It might not be in a draft state or another error occurred.' + ]; +} + +header('Location: view_application.php?id=' . $application_id); +exit(); diff --git a/view_application.php b/view_application.php index 98a0842..53223a7 100644 --- a/view_application.php +++ b/view_application.php @@ -1,5 +1,6 @@ 'Sales Manager', + 2 => 'General Manager', + 3 => 'Managing Director', + 4 => 'Accounts', + 5 => 'IT' +]; +// --- End New Approval Workflow --- + // Fetch application details -$stmt = $pdo->prepare('SELECT * FROM customer_applications WHERE id = ?'); +$stmt = $pdo->prepare('SELECT a.*, r.name as current_approver_role FROM customer_applications a LEFT JOIN roles r ON a.current_approver_role_id = r.id WHERE a.id = ?'); $stmt->execute([$application_id]); $application = $stmt->fetch(); @@ -22,30 +33,27 @@ if (!$application) { die('Application not found.'); } -// Fetch contacts -$stmt = $pdo->prepare('SELECT * FROM customer_contacts WHERE customer_application_id = ?'); -$stmt->execute([$application_id]); -$contacts = $stmt->fetchAll(); +// Fetch approval history +$stmt_history = $pdo->prepare('SELECT ah.*, u.username as approver_name FROM application_approvals ah JOIN users u ON ah.approver_id = u.id WHERE ah.application_id = ? ORDER BY ah.created_at DESC'); +$stmt_history->execute([$application_id]); +$approval_history = $stmt_history->fetchAll(); -// Fetch addresses -$stmt = $pdo->prepare('SELECT * FROM customer_addresses WHERE customer_application_id = ?'); -$stmt->execute([$application_id]); -$addresses = $stmt->fetchAll(); +// Fetch other details (contacts, addresses, etc.) - condensed for brevity +$contacts = $pdo->query("SELECT * FROM customer_contacts WHERE customer_application_id = {$application_id}")->fetchAll(); +$addresses = $pdo->query("SELECT * FROM customer_addresses WHERE customer_application_id = {$application_id}")->fetchAll(); +$trade_references = $pdo->query("SELECT * FROM customer_trade_references WHERE customer_application_id = {$application_id}")->fetchAll(); +$bank_details = $pdo->query("SELECT * FROM customer_bank_details WHERE customer_application_id = {$application_id}")->fetch(); +$principals = $pdo->query("SELECT * FROM customer_principals WHERE customer_application_id = {$application_id}")->fetchAll(); -// Fetch trade references -$stmt = $pdo->prepare('SELECT * FROM customer_trade_references WHERE customer_application_id = ?'); -$stmt->execute([$application_id]); -$trade_references = $stmt->fetchAll(); +// Get current user role +$current_user_role_id = get_user_role_id(); +$stmt_role = $pdo->prepare("SELECT name FROM roles WHERE id = ?"); +$stmt_role->execute([$current_user_role_id]); +$current_user_role_name = $stmt_role->fetchColumn(); -// Fetch bank details -$stmt = $pdo->prepare('SELECT * FROM customer_bank_details WHERE customer_application_id = ?'); -$stmt->execute([$application_id]); -$bank_details = $stmt->fetch(); - -// Fetch principals -$stmt = $pdo->prepare('SELECT * FROM customer_principals WHERE customer_application_id = ?'); -$stmt->execute([$application_id]); -$principals = $stmt->fetchAll(); +$current_level = $application['approval_level']; +$required_role = $approval_levels[$current_level] ?? null; +$can_approve = ($current_user_role_name === $required_role || $current_user_role_name === 'admin'); ?> @@ -60,349 +68,125 @@ $principals = $stmt->fetchAll(); +
+ + + + +

Application Details:

- +
-
Company Details
+
Approval Status & History
-

Company Name:

-

Company Website:

-

Company Phone:

-

Sales Owner:

-

Payment Terms:

-

Tags:

-

Notes:

-
-
+

Current Status: + + + +

+ +

Waiting for approval from:

+ - -
-
Financial & Credit Details
-
-

Major Product:

-

Capital:

-

Main Shareholders:

-

Number of Employees:

-

Payment Terms AR:

-
-
P/L Information
-

Year:

-

Net Sales:

-

Net Income Margin:

-

Net Income Margin Ratio: %

-
-
ROHM Sales Target (KUS$)
-

This Year:

-

Next Year:

-

After the Next:

-
-
Credit Information
-

Rank:

-

Limit: KUS$

-
-
Credit Research
-

Status:

-

Reason:

-
-

Tax Rate/Area (GST TYPE):

-

Billing Type:

-
-
+ +
+ + +
+ - -
-
Del-To Informations
-
-

Del-To Code:

-

Abbreviation of Delivery-To:

-

Customer Name:

-

Address:
-
- -
- - -
- - -
- -

-

Postcode (Zip Code):

-

Phone Number:

-

Area Code:

-

Transportation Code:

-

Stock Point Code:

-

Recipient Section:

-

Country Code:

-

Shipment Flag:

-

Number of Date for Transport:

-

Shipment Condition: Category:

-

Transport Service Exist:

-

Shipment Condition: Place:

-
-
- - -
-
SOP
-
-
-
-
Document Requirements
-

D/O*:

-

Packing List*:

-

Invoice*:

-

Export Permit:

-

1 PO/1 DO/1 INV:

-

1 DO/1 INV:

-

Others:

-
-
-
Packing Requirements
-

One Line One Carton:

-

One Item One Carton:

-

One Item One Pocket:

-

Special Thomson Label:

-

Special Contents Label:

-

Delivery schedule:

-
-
-
-
Forwarder Information
-

Forwarder Name:

-

Forwarder Code:

-

Forwarder Address:

-

Contact Person:

-

Phone:

-

Fax:

-

Delivery Method:

-

Delivery Timings:

-

Delivery Requirements:

-
-
Special Instructions
-

Shipping Mark:

-

Fax Documents:

-

Details:

-

Attention To:

-

Fax Number:

-

Remarks:

-
-
- - -
-
Contacts
-
- -
-

Name:

-

Email:

-

Phone:

-
- -
-
- - -
-
Addresses
-
- -
-

Type:

-

Address:
-
- -
- - ,
- -

-
- -
-
- - -
-
Trade References
-
- -
-

Company Name:

-

Contact Person:

-

Email:

-

Phone:

-

Address:

-
- -
-
- - -
-
Bank Details
-
-

Bank Name:

-

Branch:

-

BSB Number:

-

Account Number:

-

Account Name:

-
-
- - -
-
Declaration and Signature
-
-

Declaration:

- -

Signature:

- Signature +
Approval History
+ +

No approval history found.

-

No signature provided.

+
    + +
  • +

    Action:

    +

    By:

    + +

    Comments:

    + + +
  • + +
- -
-
Application Summary
-
-
Company Details
-
-
-

Customer Name:

-

Major Product of Customer:

-

Capital:

-

Main Shareholders:

-

Number of Employee:

-

Payment Terms AR:

-
-
-
Customer's P/L Information
-

Year:

-

Net Sales:

-

Net Income Margin:

-

Net Income Margin Ratio(%):

-
-
-
-
-
-
ROHM Sales Target
-

This Year: KUS$

-

Next Year: KUS$

-

After the Next: KUS$

-
-
-
Credit Information
-

Rank:

-

Limit (KUS$):

-
-
-
-
-
-
Credit Research
-

Status:

-

Reason:

-
-
-
Other Details
-

Tax Rate/Area (GST TYPE):

-

Billing Type:

-
-
-
-
- -
-
Principals Summary
-
- -
-

Name:

-

Title:

-

Ownership %:

-
- -
-
- -
-
Contacts Summary
-
- -
-

Name:

-

Email:

-

Phone:

-
- -
-
- -
-
Trade References Summary
-
- -
-

Company Name:

-

Contact Person:

-

Email:

-

Phone:

-
- -
-
- -
-
Bank Reference Summary
-
-

Bank Name:

-

Branch:

-

Account Number:

-

Account Name:

-
-
- - - + +
Approval Action
+
+ + +
+ 1): // Cannot return from the first level ?> + +
+ + + +
+
+ +
+
Company Details
+
+

Company Name:

+

Company Website:

+

Company Phone:

+
+
+
+
+ +
+
Application Summary
+
+

Test: Test

+
+
+
+
+
+ \ No newline at end of file