V1.001 expanded requirements
BIN
assets/pasted-20251204-015537-032cd7e6.png
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
assets/pasted-20251204-015710-55b153a5.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
assets/pasted-20251204-015859-ba057228.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
assets/pasted-20251204-015945-278d0108.png
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
assets/pasted-20251204-020809-fbe187c3.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
assets/pasted-20251204-021404-14f90d2d.png
Normal file
|
After Width: | Height: | Size: 203 KiB |
BIN
assets/pasted-20251204-021710-6689afd9.png
Normal file
|
After Width: | Height: | Size: 214 KiB |
BIN
assets/pasted-20251204-022151-982a3976.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
assets/pasted-20251204-022306-1a04c023.png
Normal file
|
After Width: | Height: | Size: 117 KiB |
BIN
assets/pasted-20251204-022406-7fe85bc3.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
assets/pasted-20251204-022454-940b0a04.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
assets/pasted-20251204-022551-bbe9e793.png
Normal file
|
After Width: | Height: | Size: 136 KiB |
BIN
assets/pasted-20251204-022908-1d2c298f.png
Normal file
|
After Width: | Height: | Size: 321 KiB |
51
auth.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$username = $_POST['username'] ?? '';
|
||||
$password = $_POST['password'] ?? '';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("SELECT u.id, u.username, u.password, r.name as role_name
|
||||
FROM users u
|
||||
JOIN roles r ON u.role_id = r.id
|
||||
WHERE u.username = ?");
|
||||
$stmt->execute([$username]);
|
||||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
// Authentication successful
|
||||
$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']]);
|
||||
$permissions = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
$_SESSION['user'] = [
|
||||
'id' => $user['id'],
|
||||
'username' => $user['username'],
|
||||
'role' => $user['role_name'],
|
||||
'permissions' => $permissions
|
||||
];
|
||||
unset($_SESSION['error']);
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
} else {
|
||||
// Authentication failed
|
||||
$_SESSION['error'] = 'Invalid username or password.';
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$_SESSION['error'] = 'Database error: ' . $e->getMessage();
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
}
|
||||
} else {
|
||||
// Redirect if accessed directly
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
}
|
||||
39
db/migrations/001_create_customer_tables.sql
Normal file
@ -0,0 +1,39 @@
|
||||
CREATE TABLE IF NOT EXISTS `customer_applications` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`application_id` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`customer_id` VARCHAR(255) NULL,
|
||||
`company_name` VARCHAR(255) NOT NULL,
|
||||
`company_website` VARCHAR(255) NULL,
|
||||
`company_phone` VARCHAR(255) NULL,
|
||||
`sales_owner` VARCHAR(255) NOT NULL,
|
||||
`payment_terms` VARCHAR(255) NOT NULL,
|
||||
`tags` TEXT NULL,
|
||||
`notes` TEXT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'DRAFT',
|
||||
`created_by` VARCHAR(255) NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `customer_contacts` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`customer_application_id` INT NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`email` VARCHAR(255) NOT NULL,
|
||||
`phone` VARCHAR(255) NULL,
|
||||
`is_primary` BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
FOREIGN KEY (`customer_application_id`) REFERENCES `customer_applications`(`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `customer_addresses` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`customer_application_id` INT NOT NULL,
|
||||
`address_type` VARCHAR(50) NOT NULL, -- e.g., 'BILLING', 'SHIPPING'
|
||||
`address_line_1` VARCHAR(255) NOT NULL,
|
||||
`address_line_2` VARCHAR(255) NULL,
|
||||
`city` VARCHAR(255) NOT NULL,
|
||||
`state` VARCHAR(255) NOT NULL,
|
||||
`postal_code` VARCHAR(50) NOT NULL,
|
||||
`country` VARCHAR(100) NOT NULL,
|
||||
FOREIGN KEY (`customer_application_id`) REFERENCES `customer_applications`(`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
8
db/migrations/002_create_application_files_table.sql
Normal file
@ -0,0 +1,8 @@
|
||||
CREATE TABLE IF NOT EXISTS `application_files` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`customer_application_id` INT NOT NULL,
|
||||
`filename` VARCHAR(255) NOT NULL,
|
||||
`filepath` VARCHAR(255) NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`customer_application_id`) REFERENCES `customer_applications`(`id`) ON DELETE CASCADE
|
||||
);
|
||||
58
db/migrations/003_create_user_management_tables.sql
Normal file
@ -0,0 +1,58 @@
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`username` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`password` VARCHAR(255) NOT NULL,
|
||||
`role_id` INT NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `roles` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` VARCHAR(255) NOT NULL UNIQUE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `permissions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` VARCHAR(255) NOT NULL UNIQUE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `role_permissions` (
|
||||
`role_id` INT NOT NULL,
|
||||
`permission_id` INT NOT NULL,
|
||||
PRIMARY KEY (`role_id`, `permission_id`),
|
||||
FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE CASCADE,
|
||||
FOREIGN KEY (`permission_id`) REFERENCES `permissions`(`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
INSERT IGNORE INTO `roles` (`name`) VALUES ('admin'), ('manager'), ('sales'), ('clerk');
|
||||
|
||||
INSERT IGNORE INTO `permissions` (`name`) VALUES
|
||||
('create_application'),
|
||||
('edit_application'),
|
||||
('approve_application'),
|
||||
('view_applications'),
|
||||
('delete_application'),
|
||||
('manage_users'),
|
||||
('manage_roles'),
|
||||
('upload_files'),
|
||||
('delete_files');
|
||||
|
||||
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT (SELECT id FROM roles WHERE name = 'admin'), id FROM permissions;
|
||||
|
||||
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT (SELECT id FROM roles WHERE name = 'manager'), p.id
|
||||
FROM permissions p
|
||||
WHERE p.name IN ('create_application', 'edit_application', 'approve_application', 'view_applications', 'delete_application', 'upload_files', 'delete_files');
|
||||
|
||||
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT (SELECT id FROM roles WHERE name = 'sales'), p.id
|
||||
FROM permissions p
|
||||
WHERE p.name IN ('create_application', 'edit_application', 'view_applications', 'upload_files', 'delete_files');
|
||||
|
||||
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT (SELECT id FROM roles WHERE name = 'clerk'), p.id
|
||||
FROM permissions p
|
||||
WHERE p.name = 'view_applications';
|
||||
|
||||
INSERT IGNORE INTO `users` (`username`, `password`, `role_id`) VALUES ('admin', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', (SELECT id FROM roles WHERE name = 'admin')); -- password is 'password'
|
||||
13
db/migrations/004_add_approval_workflow_columns.sql
Normal file
@ -0,0 +1,13 @@
|
||||
ALTER TABLE customer_applications ADD COLUMN approval_level INT DEFAULT 1;
|
||||
ALTER TABLE customer_applications ADD COLUMN current_approver_role_id INT;
|
||||
CREATE TABLE IF NOT EXISTS application_approvals (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
application_id INT NOT NULL,
|
||||
approver_id INT NOT NULL,
|
||||
approval_level INT NOT NULL,
|
||||
status VARCHAR(255) NOT NULL,
|
||||
comments TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (application_id) REFERENCES customer_applications(id),
|
||||
FOREIGN KEY (approver_id) REFERENCES users(id)
|
||||
);
|
||||
45
db/migrations/005_create_approver_roles.sql
Normal file
@ -0,0 +1,45 @@
|
||||
INSERT IGNORE INTO `roles` (`name`) VALUES
|
||||
('Approver Level 1'),
|
||||
('Approver Level 2'),
|
||||
('Approver Level 3'),
|
||||
('Approver Level 4'),
|
||||
('Approver Level 5'),
|
||||
('Approver Level 6'),
|
||||
('Approver Level 7');
|
||||
|
||||
INSERT IGNORE INTO `permissions` (`name`) VALUES
|
||||
('approve_level_1'),
|
||||
('approve_level_2'),
|
||||
('approve_level_3'),
|
||||
('approve_level_4'),
|
||||
('approve_level_5'),
|
||||
('approve_level_6'),
|
||||
('approve_level_7');
|
||||
|
||||
-- Assign approve_level_1 permission to Approver Level 1 role
|
||||
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT (SELECT id FROM roles WHERE name = 'Approver Level 1'), (SELECT id FROM permissions WHERE name = 'approve_level_1');
|
||||
|
||||
-- Assign approve_level_2 permission to Approver Level 2 role
|
||||
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT (SELECT id FROM roles WHERE name = 'Approver Level 2'), (SELECT id FROM permissions WHERE name = 'approve_level_2');
|
||||
|
||||
-- Assign approve_level_3 permission to Approver Level 3 role
|
||||
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT (SELECT id FROM roles WHERE name = 'Approver Level 3'), (SELECT id FROM permissions WHERE name = 'approve_level_3');
|
||||
|
||||
-- Assign approve_level_4 permission to Approver Level 4 role
|
||||
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT (SELECT id FROM roles WHERE name = 'Approver Level 4'), (SELECT id FROM permissions WHERE name = 'approve_level_4');
|
||||
|
||||
-- Assign approve_level_5 permission to Approver Level 5 role
|
||||
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT (SELECT id FROM roles WHERE name = 'Approver Level 5'), (SELECT id FROM permissions WHERE name = 'approve_level_5');
|
||||
|
||||
-- Assign approve_level_6 permission to Approver Level 6 role
|
||||
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT (SELECT id FROM roles WHERE name = 'Approver Level 6'), (SELECT id FROM permissions WHERE name = 'approve_level_6');
|
||||
|
||||
-- Assign approve_level_7 permission to Approver Level 7 role
|
||||
INSERT IGNORE INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT (SELECT id FROM roles WHERE name = 'Approver Level 7'), (SELECT id FROM permissions WHERE name = 'approve_level_7');
|
||||
31
db/migrations/006_add_trade_ref_bank_and_signature.sql
Normal file
@ -0,0 +1,31 @@
|
||||
-- Add new tables for trade references and bank details
|
||||
CREATE TABLE IF NOT EXISTS `customer_trade_references` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`customer_application_id` int(11) NOT NULL,
|
||||
`company_name` varchar(255) NOT NULL,
|
||||
`contact_person` varchar(255) DEFAULT NULL,
|
||||
`email` varchar(255) DEFAULT NULL,
|
||||
`phone` varchar(50) DEFAULT NULL,
|
||||
`address` text,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `customer_application_id` (`customer_application_id`),
|
||||
CONSTRAINT `customer_trade_references_ibfk_1` FOREIGN KEY (`customer_application_id`) REFERENCES `customer_applications` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `customer_bank_details` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`customer_application_id` int(11) NOT NULL,
|
||||
`bank_name` varchar(255) DEFAULT NULL,
|
||||
`branch` varchar(255) DEFAULT NULL,
|
||||
`bsb_number` varchar(50) DEFAULT NULL,
|
||||
`account_number` varchar(50) DEFAULT NULL,
|
||||
`account_name` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `customer_application_id` (`customer_application_id`),
|
||||
CONSTRAINT `customer_bank_details_ibfk_1` FOREIGN KEY (`customer_application_id`) REFERENCES `customer_applications` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Add columns for declaration and signature to customer_applications
|
||||
ALTER TABLE `customer_applications`
|
||||
ADD COLUMN `declaration_text` TEXT,
|
||||
ADD COLUMN `signature_path` VARCHAR(255);
|
||||
20
db/migrations/007_add_financial_credit_details.sql
Normal file
@ -0,0 +1,20 @@
|
||||
ALTER TABLE `customer_applications`
|
||||
ADD COLUMN `major_product` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `capital` DECIMAL(20, 2) DEFAULT NULL,
|
||||
ADD COLUMN `capital_currency` VARCHAR(10) DEFAULT NULL,
|
||||
ADD COLUMN `main_shareholders` TEXT DEFAULT NULL,
|
||||
ADD COLUMN `num_employees` INT DEFAULT NULL,
|
||||
ADD COLUMN `payment_terms_ar` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `pl_year` YEAR DEFAULT NULL,
|
||||
ADD COLUMN `net_sales` DECIMAL(20, 2) DEFAULT NULL,
|
||||
ADD COLUMN `net_income_margin` DECIMAL(20, 2) DEFAULT NULL,
|
||||
ADD COLUMN `net_income_margin_ratio` DECIMAL(5, 2) DEFAULT NULL,
|
||||
ADD COLUMN `sales_target_this_year` DECIMAL(20, 2) DEFAULT NULL,
|
||||
ADD COLUMN `sales_target_next_year` DECIMAL(20, 2) DEFAULT NULL,
|
||||
ADD COLUMN `sales_target_after_next` DECIMAL(20, 2) DEFAULT NULL,
|
||||
ADD COLUMN `credit_rank` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `credit_limit` DECIMAL(20, 2) DEFAULT NULL,
|
||||
ADD COLUMN `credit_research_status` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `credit_research_reason` TEXT DEFAULT NULL,
|
||||
ADD COLUMN `tax_rate_area` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `billing_type` VARCHAR(255) DEFAULT NULL;
|
||||
21
db/migrations/008_add_del_to_info.sql
Normal file
@ -0,0 +1,21 @@
|
||||
-- Add columns for DEL-TO INFORMATIONS
|
||||
ALTER TABLE `customer_applications`
|
||||
ADD COLUMN `del_to_code` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `delivery_abbreviation` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_customer_name` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_address_1` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_address_2` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_address_3` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_address_4` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_postcode` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_phone` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_area_code` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_transportation_code` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_stock_point_code` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_recipient_section` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_country_code` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_shipment_flag` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_transport_days` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_shipment_condition_category` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_transport_service_exist` VARCHAR(255) DEFAULT NULL,
|
||||
ADD COLUMN `del_to_shipment_condition_place` VARCHAR(255) DEFAULT NULL;
|
||||
29
db/migrations/009_add_sop_details.sql
Normal file
@ -0,0 +1,29 @@
|
||||
ALTER TABLE `customer_applications`
|
||||
ADD COLUMN `doc_req_do` VARCHAR(255),
|
||||
ADD COLUMN `doc_req_packing_list` VARCHAR(255),
|
||||
ADD COLUMN `doc_req_invoice` VARCHAR(255),
|
||||
ADD COLUMN `doc_req_export_permit` VARCHAR(255),
|
||||
ADD COLUMN `doc_req_po_do_inv` VARCHAR(255),
|
||||
ADD COLUMN `doc_req_do_inv` VARCHAR(255),
|
||||
ADD COLUMN `doc_req_others` TEXT,
|
||||
ADD COLUMN `pack_req_one_line_carton` VARCHAR(255),
|
||||
ADD COLUMN `pack_req_one_item_carton` VARCHAR(255),
|
||||
ADD COLUMN `pack_req_one_item_pocket` VARCHAR(255),
|
||||
ADD COLUMN `pack_req_thomson_label` VARCHAR(255),
|
||||
ADD COLUMN `pack_req_contents_label` VARCHAR(255),
|
||||
ADD COLUMN `pack_req_delivery_schedule` VARCHAR(255),
|
||||
ADD COLUMN `forwarder_name` VARCHAR(255),
|
||||
ADD COLUMN `forwarder_code` VARCHAR(255),
|
||||
ADD COLUMN `forwarder_address` TEXT,
|
||||
ADD COLUMN `forwarder_contact_person` VARCHAR(255),
|
||||
ADD COLUMN `forwarder_phone` VARCHAR(255),
|
||||
ADD COLUMN `forwarder_fax` VARCHAR(255),
|
||||
ADD COLUMN `forwarder_delivery_method` VARCHAR(255),
|
||||
ADD COLUMN `forwarder_delivery_timings` VARCHAR(255),
|
||||
ADD COLUMN `forwarder_delivery_requirements` TEXT,
|
||||
ADD COLUMN `special_instructions_shipping_mark` VARCHAR(255),
|
||||
ADD COLUMN `special_instructions_fax_documents` VARCHAR(255),
|
||||
ADD COLUMN `special_instructions_details` TEXT,
|
||||
ADD COLUMN `special_instructions_attention_to` VARCHAR(255),
|
||||
ADD COLUMN `special_instructions_fax_number` VARCHAR(255),
|
||||
ADD COLUMN `remarks` TEXT;
|
||||
59
delete_file.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'includes/auth_helpers.php';
|
||||
redirect_if_not_authenticated();
|
||||
redirect_if_no_permission('delete_files');
|
||||
|
||||
require_once 'db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$file_id = $_POST['file_id'] ?? null;
|
||||
$application_id = $_POST['application_id'] ?? null;
|
||||
|
||||
if (!$file_id || !$application_id) {
|
||||
$_SESSION['message'] = 'Invalid request.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// First, get the filename to delete it from the server
|
||||
$stmt = $pdo->prepare("SELECT stored_filename FROM application_files WHERE id = ? AND application_id = ?");
|
||||
$stmt->execute([$file_id, $application_id]);
|
||||
$file = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($file) {
|
||||
$filepath = __DIR__ . '/uploads/' . $file['stored_filename'];
|
||||
|
||||
// Delete the file from the filesystem
|
||||
if (file_exists($filepath)) {
|
||||
unlink($filepath);
|
||||
}
|
||||
|
||||
// Delete the record from the database
|
||||
$delete_stmt = $pdo->prepare("DELETE FROM application_files WHERE id = ?");
|
||||
$delete_stmt->execute([$file_id]);
|
||||
|
||||
$_SESSION['message'] = 'File deleted successfully.';
|
||||
$_SESSION['message_type'] = 'success';
|
||||
} else {
|
||||
$_SESSION['message'] = 'File not found or you do not have permission to delete it.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// In a real app, log this error
|
||||
$_SESSION['message'] = 'Database error while deleting file.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
}
|
||||
|
||||
header('Location: view_application.php?id=' . $application_id);
|
||||
exit();
|
||||
|
||||
} else {
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
282
edit_application.php
Normal file
@ -0,0 +1,282 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'includes/auth_helpers.php';
|
||||
redirect_if_not_authenticated();
|
||||
redirect_if_no_permission('edit_application');
|
||||
|
||||
require_once 'db/config.php';
|
||||
|
||||
$application_id = $_GET['id'] ?? null;
|
||||
if (!$application_id) {
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$customer = null;
|
||||
$contacts = [];
|
||||
$addresses = [];
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// Fetch customer
|
||||
$stmt = $pdo->prepare("SELECT * FROM customer_applications WHERE id = ?");
|
||||
$stmt->execute([$application_id]);
|
||||
$customer = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($customer) {
|
||||
// Fetch contacts
|
||||
$stmt = $pdo->prepare("SELECT * FROM customer_contacts WHERE customer_application_id = ? ORDER BY is_primary DESC, id ASC");
|
||||
$stmt->execute([$application_id]);
|
||||
$contacts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Fetch addresses
|
||||
$stmt = $pdo->prepare("SELECT * FROM customer_addresses WHERE customer_application_id = ? ORDER BY id ASC");
|
||||
$stmt->execute([$application_id]);
|
||||
$addresses = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Fetch files
|
||||
$stmt = $pdo->prepare("SELECT * FROM application_files WHERE customer_application_id = ? ORDER BY created_at DESC");
|
||||
$stmt->execute([$application_id]);
|
||||
$files = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
die("Database error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
if (!$customer) {
|
||||
http_response_code(404);
|
||||
echo "Application not found.";
|
||||
exit();
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Customer Application</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Customer Master</a>
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Dashboard</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="logout.php">Logout</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container mt-4">
|
||||
<h2>Edit Customer Application #<?php echo $customer['id']; ?></h2>
|
||||
<form action="update_application.php" method="POST" id="applicationForm" enctype="multipart/form-data">
|
||||
<input type="hidden" name="customer_id" value="<?php echo $customer['id']; ?>">
|
||||
|
||||
<!-- Company Details -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Company Details</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="company_name" class="form-label">Company Name</label>
|
||||
<input type="text" class="form-control" id="company_name" name="company_name" value="<?php echo htmlspecialchars($customer['company_name']); ?>" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="company_website" class="form-label">Company Website</label>
|
||||
<input type="url" class="form-control" id="company_website" name="company_website" value="<?php echo htmlspecialchars($customer['company_website']); ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="company_phone" class="form-label">Company Phone</label>
|
||||
<input type="tel" class="form-control" id="company_phone" name="company_phone" value="<?php echo htmlspecialchars($customer['company_phone']); ?>">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="sales_owner" class="form-label">Sales Owner</label>
|
||||
<input type="text" class="form-control" id="sales_owner" name="sales_owner" value="<?php echo htmlspecialchars($customer['sales_owner']); ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="payment_terms" class="form-label">Payment Terms</label>
|
||||
<input type="text" class="form-control" id="payment_terms" name="payment_terms" value="<?php echo htmlspecialchars($customer['payment_terms']); ?>" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="tags" class="form-label">Tags</label>
|
||||
<input type="text" class="form-control" id="tags" name="tags" value="<?php echo htmlspecialchars($customer['tags']); ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="notes" class="form-label">Notes</label>
|
||||
<textarea class="form-control" id="notes" name="notes" rows="3"><?php echo htmlspecialchars($customer['notes']); ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contacts -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
Contacts
|
||||
<button type="button" class="btn btn-sm btn-primary" id="addContact"><i class="bi bi-plus-circle"></i> Add Contact</button>
|
||||
</div>
|
||||
<div class="card-body" id="contactsContainer">
|
||||
<?php foreach ($contacts as $index => $contact): ?>
|
||||
<div class="contact-group border p-3 mb-3">
|
||||
<input type="hidden" name="contact[<?php echo $index; ?>][id]" value="<?php echo $contact['id']; ?>">
|
||||
<button type="button" class="btn-close float-end" aria-label="Close" onclick="if(confirm('Are you sure you want to delete this contact?')) { this.parentElement.remove(); }"></button>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="radio" name="contact[<?php echo $index; ?>][is_primary]" id="contact_<?php echo $index; ?>_is_primary" value="1" <?php echo $contact['is_primary'] ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="contact_<?php echo $index; ?>_is_primary">Primary Contact</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3"><input type="text" name="contact[<?php echo $index; ?>][name]" class="form-control" placeholder="Name" value="<?php echo htmlspecialchars($contact['name']); ?>" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="email" name="contact[<?php echo $index; ?>][email]" class="form-control" placeholder="Email" value="<?php echo htmlspecialchars($contact['email']); ?>" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="tel" name="contact[<?php echo $index; ?>][phone]" class="form-control" placeholder="Phone" value="<?php echo htmlspecialchars($contact['phone']); ?>"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Addresses -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
Addresses
|
||||
<button type="button" class="btn btn-sm btn-primary" id="addAddress"><i class="bi bi-plus-circle"></i> Add Address</button>
|
||||
</div>
|
||||
<div class="card-body" id="addressesContainer">
|
||||
<?php foreach ($addresses as $index => $address): ?>
|
||||
<div class="address-group border p-3 mb-3">
|
||||
<input type="hidden" name="address[<?php echo $index; ?>][id]" value="<?php echo $address['id']; ?>">
|
||||
<button type="button" class="btn-close float-end" aria-label="Close" onclick="if(confirm('Are you sure you want to delete this address?')) { this.parentElement.remove(); }"></button>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<select name="address[<?php echo $index; ?>][type]" class="form-select" required>
|
||||
<option value="BILLING" <?php echo $address['address_type'] === 'BILLING' ? 'selected' : ''; ?>>Billing</option>
|
||||
<option value="SHIPPING" <?php echo $address['address_type'] === 'SHIPPING' ? 'selected' : ''; ?>>Shipping</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3"><input type="text" name="address[<?php echo $index; ?>][line1]" class="form-control" placeholder="Address Line 1" value="<?php echo htmlspecialchars($address['street']); ?>" required></div>
|
||||
<div class="mb-3"><input type="text" name="address[<?php echo $index; ?>][line2]" class="form-control" placeholder="Address Line 2" value="<?php echo htmlspecialchars($address['street2']); ?>"></div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[<?php echo $index; ?>][city]" class="form-control" placeholder="City" value="<?php echo htmlspecialchars($address['city']); ?>" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[<?php echo $index; ?>][state]" class="form-control" placeholder="State/Province" value="<?php echo htmlspecialchars($address['state']); ?>" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[<?php echo $index; ?>][postal_code]" class="form-control" placeholder="Postal Code" value="<?php echo htmlspecialchars($address['zip_code']); ?>" required></div>
|
||||
</div>
|
||||
<div class="mb-3"><input type="text" name="address[<?php echo $index; ?>][country]" class="form-control" placeholder="Country" value="<?php echo htmlspecialchars($address['country']); ?>" required></div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- File Uploads -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">File Uploads</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="fileUpload" class="form-label">Upload New File</label>
|
||||
<div class="input-group">
|
||||
<input type="file" class="form-control" id="fileUpload" name="file_upload">
|
||||
<button class="btn btn-outline-secondary" type="submit" name="upload_file">Upload</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<h5>Uploaded Files</h5>
|
||||
<ul class="list-group">
|
||||
<?php if (empty($files)): ?>
|
||||
<li class="list-group-item">No files uploaded yet.</li>
|
||||
<?php else: ?>
|
||||
<?php foreach ($files as $file): ?>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<a href="uploads/<?php echo $file['filepath']; ?>" target="_blank"><?php echo htmlspecialchars($file['filename']); ?></a>
|
||||
<a href="delete_file.php?id=<?php echo $file['id']; ?>&customer_id=<?php echo $application_id; ?>" class="btn btn-danger btn-sm" onclick="return confirm('Are you sure you want to delete this file?')">Delete</a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" name="save_changes" class="btn btn-success">Save Changes</button>
|
||||
<a href="view_application.php?id=<?php echo $customer['id']; ?>" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
let contactIndex = <?php echo count($contacts); ?>;
|
||||
document.getElementById('addContact').addEventListener('click', function () {
|
||||
const container = document.getElementById('contactsContainer');
|
||||
const newContact = document.createElement('div');
|
||||
newContact.className = 'contact-group border p-3 mb-3';
|
||||
newContact.innerHTML = `
|
||||
<button type="button" class="btn-close float-end" aria-label="Close" onclick="if(confirm('Are you sure you want to delete this contact?')) { this.parentElement.remove(); }"></button>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="radio" name="contact[${contactIndex}][is_primary]" id="contact_${contactIndex}_is_primary" value="1">
|
||||
<label class="form-check-label" for="contact_${contactIndex}_is_primary">Primary Contact</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3"><input type="text" name="contact[${contactIndex}][name]" class="form-control" placeholder="Name" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="email" name="contact[${contactIndex}][email]" class="form-control" placeholder="Email" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="tel" name="contact[${contactIndex}][phone]" class="form-control" placeholder="Phone"></div>
|
||||
</div>`;
|
||||
container.appendChild(newContact);
|
||||
contactIndex++;
|
||||
updateRadioListeners();
|
||||
});
|
||||
|
||||
let addressIndex = <?php echo count($addresses); ?>;
|
||||
document.getElementById('addAddress').addEventListener('click', function () {
|
||||
const container = document.getElementById('addressesContainer');
|
||||
const newAddress = document.createElement('div');
|
||||
newAddress.className = 'address-group border p-3 mb-3';
|
||||
newAddress.innerHTML = `
|
||||
<button type="button" class="btn-close float-end" aria-label="Close" onclick="if(confirm('Are you sure you want to delete this address?')) { this.parentElement.remove(); }"></button>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<select name="address[${addressIndex}][type]" class="form-select" required>
|
||||
<option value="BILLING">Billing</option>
|
||||
<option value="SHIPPING">Shipping</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3"><input type="text" name="address[${addressIndex}][line1]" class="form-control" placeholder="Address Line 1" required></div>
|
||||
<div class="mb-3"><input type="text" name="address[${addressIndex}][line2]" class="form-control" placeholder="Address Line 2"></div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[${addressIndex}][city]" class="form-control" placeholder="City" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[${addressIndex}][state]" class="form-control" placeholder="State/Province" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[${addressIndex}][postal_code]" class="form-control" placeholder="Postal Code" required></div>
|
||||
</div>
|
||||
<div class="mb-3"><input type="text" name="address[${addressIndex}][country]" class="form-control" placeholder="Country" required></div>`;
|
||||
container.appendChild(newAddress);
|
||||
addressIndex++;
|
||||
});
|
||||
|
||||
function updateRadioListeners() {
|
||||
const radios = document.querySelectorAll('input[type="radio"][name^="contact"]');
|
||||
radios.forEach(radio => {
|
||||
radio.addEventListener('change', function() {
|
||||
if (this.checked) {
|
||||
radios.forEach(r => {
|
||||
if (r !== this) r.checked = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
updateRadioListeners();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
27
includes/auth_helpers.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
function hasPermission($permission_name) {
|
||||
if (isset($_SESSION['user']['permissions']) && in_array($permission_name, $_SESSION['user']['permissions'])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function redirect_if_not_authenticated() {
|
||||
if (!isset($_SESSION['user'])) {
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
function redirect_if_no_permission($permission_name) {
|
||||
if (!hasPermission($permission_name)) {
|
||||
// You can redirect to a specific error page or the index page with an error message.
|
||||
$_SESSION['flash_message'] = [
|
||||
'type' => 'danger',
|
||||
'message' => 'You do not have permission to access this page.'
|
||||
];
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
351
index.php
@ -1,150 +1,217 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
@ini_set('display_errors', '1');
|
||||
@error_reporting(E_ALL);
|
||||
@date_default_timezone_set('UTC');
|
||||
session_start();
|
||||
require_once 'includes/auth_helpers.php';
|
||||
|
||||
// Protect route: check if user is logged in
|
||||
if (!isset($_SESSION['user'])) {
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$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'] ?? '';
|
||||
|
||||
$phpVersion = PHP_VERSION;
|
||||
$now = date('Y-m-d H:i:s');
|
||||
?>
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>New Style</title>
|
||||
<?php
|
||||
// Read project preview data from environment
|
||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
|
||||
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
?>
|
||||
<?php if ($projectDescription): ?>
|
||||
<!-- Meta description -->
|
||||
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
|
||||
<!-- Open Graph meta tags -->
|
||||
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<!-- Twitter meta tags -->
|
||||
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<?php endif; ?>
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<!-- Open Graph image -->
|
||||
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<!-- Twitter image -->
|
||||
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<?php endif; ?>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
@keyframes bg-pan {
|
||||
0% { background-position: 0% 0%; }
|
||||
100% { background-position: 100% 100%; }
|
||||
}
|
||||
main {
|
||||
padding: 2rem;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.loader {
|
||||
margin: 1.25rem auto 1.25rem;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
.hint {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px; height: 1px;
|
||||
padding: 0; margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap; border: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1rem;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
code {
|
||||
background: rgba(0,0,0,0.2);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Dashboard - <?php echo htmlspecialchars($projectName); ?></title>
|
||||
<meta name="description" content="<?php echo htmlspecialchars($projectDescription); ?>">
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="<?php echo htmlspecialchars($projectName); ?>">
|
||||
<meta property="og:description" content="<?php echo htmlspecialchars($projectDescription); ?>">
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<meta property="og:image" content="<?php echo htmlspecialchars($projectImageUrl); ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:title" content="<?php echo htmlspecialchars($projectName); ?>">
|
||||
<meta property="twitter:description" content="<?php echo htmlspecialchars($projectDescription); ?>">
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<meta property="twitter:image" content="<?php echo htmlspecialchars($projectImageUrl); ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your website…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
</div>
|
||||
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
||||
</footer>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#"><i class="bi bi-person-vcard"></i> <?php echo htmlspecialchars($projectName); ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mainNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="mainNav">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#">Dashboard</a>
|
||||
</li>
|
||||
<?php if (hasPermission('manage_users')): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="manage_users.php">Manage Users</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="view_applications.php">View Applications</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-person-circle"></i> <?php echo htmlspecialchars($user['username']); ?>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="profile.php">Profile</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="logout.php"><i class="bi bi-box-arrow-right"></i> Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="container mt-4">
|
||||
<?php if (isset($_SESSION['flash_message'])): ?>
|
||||
<div class="alert alert-<?php echo $_SESSION['flash_message']['type']; ?> alert-dismissible fade show" role="alert">
|
||||
<?php echo $_SESSION['flash_message']['message']; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php unset($_SESSION['flash_message']); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="h3">Dashboard</h1>
|
||||
<?php if (hasPermission('create_application')): ?>
|
||||
<a href="new_application.php" class="btn btn-primary"><i class="bi bi-plus-circle"></i> New Customer Application</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<p>Your dashboard is ready. From here you can manage customer applications.</p>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0"><i class="bi bi-card-list"></i> Submitted Applications</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="index.php" method="GET" class="row g-3 align-items-center mb-3">
|
||||
<div class="col-auto">
|
||||
<label for="statusFilter" class="col-form-label">Filter by Status:</label>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<select name="status" id="statusFilter" class="form-select">
|
||||
<option value="">All</option>
|
||||
<option value="draft" <?php echo (($_GET['status'] ?? '') === 'draft' ? 'selected' : ''); ?>>Draft</option>
|
||||
<option value="pending_approval" <?php echo (($_GET['status'] ?? '') === 'pending_approval' ? 'selected' : ''); ?>>Pending Approval</option>
|
||||
<option value="approved" <?php echo (($_GET['status'] ?? '') === 'approved' ? 'selected' : ''); ?>>Approved</option>
|
||||
<option value="rejected" <?php echo (($_GET['status'] ?? '') === 'rejected' ? 'selected' : ''); ?>>Rejected</option>
|
||||
<option value="reverted" <?php echo (($_GET['status'] ?? '') === 'reverted' ? 'selected' : ''); ?>>Reverted</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-info">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
function getSortIcon($column, $sort_column, $sort_order) {
|
||||
if ($column === $sort_column) {
|
||||
return $sort_order === 'ASC' ? ' <i class="bi bi-arrow-up"></i>' : ' <i class="bi bi-arrow-down"></i>';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function getStatusBadgeClass($status) {
|
||||
switch ($status) {
|
||||
case 'pending_approval':
|
||||
return 'bg-warning';
|
||||
case 'approved':
|
||||
return 'bg-success';
|
||||
case 'rejected':
|
||||
return 'bg-danger';
|
||||
case 'reverted':
|
||||
return 'bg-info';
|
||||
case 'draft':
|
||||
default:
|
||||
return 'bg-secondary';
|
||||
}
|
||||
}
|
||||
|
||||
$sort_column = $_GET['sort'] ?? 'created_at';
|
||||
$sort_order = $_GET['order'] ?? 'DESC';
|
||||
$valid_columns = ['id', 'application_id', 'company_name', 'status', 'created_at'];
|
||||
if (!in_array($sort_column, $valid_columns)) {
|
||||
$sort_column = 'created_at';
|
||||
}
|
||||
|
||||
$status_filter = $_GET['status'] ?? '';
|
||||
$sql = "SELECT id, application_id, company_name, status, created_at FROM customer_applications";
|
||||
$params = [];
|
||||
|
||||
if ($status_filter) {
|
||||
$sql .= " WHERE status = ?";
|
||||
$params[] = $status_filter;
|
||||
}
|
||||
|
||||
$sql .= " ORDER BY $sort_column $sort_order";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$applications = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (count($applications) > 0) {
|
||||
echo '<table class="table table-striped table-hover">';
|
||||
echo '<thead>';
|
||||
echo '<tr>';
|
||||
echo '<th><a href="?sort=application_id&order=' . ($sort_column == 'application_id' && $sort_order == 'ASC' ? 'DESC' : 'ASC') . '&status=' . htmlspecialchars($status_filter) . '">Application ID</a>' . getSortIcon('application_id', $sort_column, $sort_order) . '</th>';
|
||||
echo '<th><a href="?sort=company_name&order=' . ($sort_column == 'company_name' && $sort_order == 'ASC' ? 'DESC' : 'ASC') . '&status=' . htmlspecialchars($status_filter) . '">Company Name</a>' . getSortIcon('company_name', $sort_column, $sort_order) . '</th>';
|
||||
echo '<th><a href="?sort=status&order=' . ($sort_column == 'status' && $sort_order == 'ASC' ? 'DESC' : 'ASC') . '&status=' . htmlspecialchars($status_filter) . '">Status</a>' . getSortIcon('status', $sort_column, $sort_order) . '</th>';
|
||||
echo '<th><a href="?sort=created_at&order=' . ($sort_column == 'created_at' && $sort_order == 'ASC' ? 'DESC' : 'ASC') . '&status=' . htmlspecialchars($status_filter) . '">Date Submitted</a>' . getSortIcon('created_at', $sort_column, $sort_order) . '</th>';
|
||||
echo '</tr>';
|
||||
echo '</thead>';
|
||||
echo '<tbody>';
|
||||
foreach ($applications as $app) { $badgeClass = getStatusBadgeClass($app['status']);
|
||||
echo '<tr>';
|
||||
echo '<td><a href="view_application.php?id=' . htmlspecialchars($app['id']) . '">' . htmlspecialchars($app['application_id']) . '</a></td>';
|
||||
echo '<td>' . htmlspecialchars($app['company_name']) . '</td>';
|
||||
echo '<td><span class="badge ' . $badgeClass . '">' . htmlspecialchars(ucfirst(str_replace('_', ' ', $app['status']))) . '</span></td>';
|
||||
echo '<td>' . htmlspecialchars(date("Y-m-d H:i", strtotime($app['created_at']))) . '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
echo '</tbody>';
|
||||
echo '</table>';
|
||||
} else {
|
||||
echo '<p class="text-center">No customer applications found.</p>';
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
echo '<div class="alert alert-danger">Error: Could not fetch applications.</div>';
|
||||
// Optional: log error to a file
|
||||
// error_log($e->getMessage());
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
65
login.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
session_start();
|
||||
// If user is already logged in, redirect to dashboard
|
||||
if (isset($_SESSION['user'])) {
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
$error = $_SESSION['error'] ?? null;
|
||||
unset($_SESSION['error']);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login - Customer Master</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.login-card {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="card login-card shadow-sm">
|
||||
<div class="card-body p-5">
|
||||
<h1 class="card-title text-center mb-4">Customer Master</h1>
|
||||
<h5 class="card-subtitle mb-4 text-center text-muted">Please sign in</h5>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<i class="bi bi-exclamation-triangle-fill"></i> <?php echo htmlspecialchars($error); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="auth.php" method="POST">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Username</label>
|
||||
<input type="text" class="form-control" id="username" name="username" required autofocus>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">Sign in</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-footer text-center text-muted py-3">
|
||||
<small>© <?php echo date("Y"); ?> <?php echo htmlspecialchars($_SERVER['PROJECT_NAME'] ?? 'Flatlogic'); ?></small>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
6
logout.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
session_start();
|
||||
session_unset();
|
||||
session_destroy();
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
185
manage_users.php
Normal file
@ -0,0 +1,185 @@
|
||||
<?php
|
||||
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');
|
||||
|
||||
$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 file upload
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['userCsv'])) {
|
||||
$file = $_FILES['userCsv'];
|
||||
|
||||
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'
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$_SESSION['flash_message'] = [
|
||||
'type' => 'danger',
|
||||
'message' => 'Error uploading file.'
|
||||
];
|
||||
}
|
||||
header('Location: manage_users.php');
|
||||
exit();
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Manage Users - <?php echo htmlspecialchars($projectName); ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="index.php"><i class="bi bi-person-vcard"></i> <?php echo htmlspecialchars($projectName); ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mainNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="mainNav">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Dashboard</a>
|
||||
</li>
|
||||
<?php if (hasPermission('manage_users')): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="manage_users.php">Manage Users</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-person-circle"></i> <?php echo htmlspecialchars($user['username']); ?>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="profile.php">Profile</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="logout.php"><i class="bi bi-box-arrow-right"></i> Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="container mt-4">
|
||||
<?php if (isset($_SESSION['flash_message'])): ?>
|
||||
<div class="alert alert-<?php echo $_SESSION['flash_message']['type']; ?> alert-dismissible fade show" role="alert">
|
||||
<?php echo $_SESSION['flash_message']['message']; ?>
|
||||
<?php if (!empty($_SESSION['flash_message']['errors'])): ?>
|
||||
<ul>
|
||||
<?php foreach ($_SESSION['flash_message']['errors'] as $error): ?>
|
||||
<li><?php echo $error; ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php unset($_SESSION['flash_message']); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<h1 class="h3 mb-4">Manage Users</h1>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Import Users from CSV</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Upload a CSV file with the following columns: <strong>username</strong>, <strong>password</strong>, <strong>role</strong>.</p>
|
||||
<form action="manage_users.php" method="post" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<label for="userCsv" class="form-label">CSV File</label>
|
||||
<input class="form-control" type="file" id="userCsv" name="userCsv" accept=".csv" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Import Users</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
780
new_application.php
Normal file
@ -0,0 +1,780 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'includes/auth_helpers.php';
|
||||
redirect_if_not_authenticated();
|
||||
redirect_if_no_permission('create_application');
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>New Customer Application</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.form-section {
|
||||
display: none;
|
||||
}
|
||||
.form-section.active {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Customer Master</a>
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Dashboard</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="logout.php">Logout</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container mt-4">
|
||||
<h2>New Customer Application</h2>
|
||||
<form action="submit_application.php" method="POST" id="applicationForm">
|
||||
<!-- Step 1: Company Details -->
|
||||
<div class="form-section active" id="step1">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Company Details</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="company_name" class="form-label">Company Name</label>
|
||||
<input type="text" class="form-control" id="company_name" name="company_name" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="company_website" class="form-label">Company Website</label>
|
||||
<input type="url" class="form-control" id="company_website" name="company_website">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="company_phone" class="form-label">Company Phone</label>
|
||||
<input type="tel" class="form-control" id="company_phone" name="company_phone">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="sales_owner" class="form-label">Sales Owner</label>
|
||||
<input type="text" class="form-control" id="sales_owner" name="sales_owner" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="payment_terms" class="form-label">Payment Terms</label>
|
||||
<input type="text" class="form-control" id="payment_terms" name="payment_terms" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="tags" class="form-label">Tags</label>
|
||||
<input type="text" class="form-control" id="tags" name="tags">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="notes" class="form-label">Notes</label>
|
||||
<textarea class="form-control" id="notes" name="notes" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: Financial & Credit Details -->
|
||||
<div class="form-section" id="step2">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Financial & Credit Details</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="major_product" class="form-label">Major Product of Customer</label>
|
||||
<input type="text" class="form-control" id="major_product" name="major_product">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="capital" class="form-label">Capital</label>
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="capital" name="capital">
|
||||
<select class="form-select" name="capital_currency">
|
||||
<option>USD</option>
|
||||
<option>EUR</option>
|
||||
<option>JPY</option>
|
||||
<option>GBP</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="main_shareholders" class="form-label">Main Shareholders</label>
|
||||
<input type="text" class="form-control" id="main_shareholders" name="main_shareholders">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="num_employees" class="form-label">Number of Employees</label>
|
||||
<input type="number" class="form-control" id="num_employees" name="num_employees">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="payment_terms_ar" class="form-label">Payment Terms AR</label>
|
||||
<input type="text" class="form-control" id="payment_terms_ar" name="payment_terms_ar">
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<h6>Customer's P/L Information</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="pl_year" class="form-label">Year</label>
|
||||
<input type="number" class="form-control" id="pl_year" name="pl_year">
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="net_sales" class="form-label">Net Sales</label>
|
||||
<input type="number" class="form-control" id="net_sales" name="net_sales">
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="net_income_margin" class="form-label">Net Income Margin</label>
|
||||
<input type="number" class="form-control" id="net_income_margin" name="net_income_margin">
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="net_income_margin_ratio" class="form-label">Net Income Margin Ratio (%)</label>
|
||||
<input type="number" class="form-control" id="net_income_margin_ratio" name="net_income_margin_ratio">
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<h6>ROHM Sales Target (KUS$)</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="sales_target_this_year" class="form-label">This Year</label>
|
||||
<input type="number" class="form-control" id="sales_target_this_year" name="sales_target_this_year">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="sales_target_next_year" class="form-label">Next Year</label>
|
||||
<input type="number" class="form-control" id="sales_target_next_year" name="sales_target_next_year">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="sales_target_after_next" class="form-label">After the Next</label>
|
||||
<input type="number" class="form-control" id="sales_target_after_next" name="sales_target_after_next">
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<h6>Credit Information</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="credit_rank" class="form-label">Rank</label>
|
||||
<input type="text" class="form-control" id="credit_rank" name="credit_rank">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="credit_limit" class="form-label">Limit (KUS$)</label>
|
||||
<input type="number" class="form-control" id="credit_limit" name="credit_limit">
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<h6>Credit Research</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="credit_research_status" class="form-label">Status</label>
|
||||
<input type="text" class="form-control" id="credit_research_status" name="credit_research_status">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="credit_research_reason" class="form-label">Reason</label>
|
||||
<input type="text" class="form-control" id="credit_research_reason" name="credit_research_reason">
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="tax_rate_area" class="form-label">Tax Rate/Area (GST TYPE)</label>
|
||||
<input type="text" class="form-control" id="tax_rate_area" name="tax_rate_area">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="billing_type" class="form-label">Billing Type</label>
|
||||
<input type="text" class="form-control" id="billing_type" name="billing_type">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: Del-To Informations -->
|
||||
<div class="form-section" id="step3">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Del-To Informations</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_code" class="form-label">Del-To Code</label>
|
||||
<input type="text" class="form-control" id="del_to_code" name="del_to_code">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="delivery_abbreviation" class="form-label">Abbreviation of Delivery-To</label>
|
||||
<input type="text" class="form-control" id="delivery_abbreviation" name="delivery_abbreviation">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="del_to_customer_name" class="form-label">Customer Name</label>
|
||||
<input type="text" class="form-control" id="del_to_customer_name" name="del_to_customer_name">
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_address_1" class="form-label">Address 1</label>
|
||||
<input type="text" class="form-control" id="del_to_address_1" name="del_to_address_1">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_address_2" class="form-label">Address 2</label>
|
||||
<input type="text" class="form-control" id="del_to_address_2" name="del_to_address_2">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_address_3" class="form-label">Address 3</label>
|
||||
<input type="text" class="form-control" id="del_to_address_3" name="del_to_address_3">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_address_4" class="form-label">Address 4</label>
|
||||
<input type="text" class="form-control" id="del_to_address_4" name="del_to_address_4">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_postcode" class="form-label">Postcode (Zip Code)</label>
|
||||
<input type="text" class="form-control" id="del_to_postcode" name="del_to_postcode">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_phone" class="form-label">Phone Number</label>
|
||||
<input type="text" class="form-control" id="del_to_phone" name="del_to_phone">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_area_code" class="form-label">Area Code</label>
|
||||
<input type="text" class="form-control" id="del_to_area_code" name="del_to_area_code">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_transportation_code" class="form-label">Transportation Code</label>
|
||||
<input type="text" class="form-control" id="del_to_transportation_code" name="del_to_transportation_code">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_stock_point_code" class="form-label">Stock Point Code</label>
|
||||
<input type="text" class="form-control" id="del_to_stock_point_code" name="del_to_stock_point_code">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_recipient_section" class="form-label">Recipient Section</label>
|
||||
<input type="text" class="form-control" id="del_to_recipient_section" name="del_to_recipient_section">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_country_code" class="form-label">Country Code</label>
|
||||
<input type="text" class="form-control" id="del_to_country_code" name="del_to_country_code">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_shipment_flag" class="form-label">Shipment Flag</label>
|
||||
<input type="text" class="form-control" id="del_to_shipment_flag" name="del_to_shipment_flag">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_transport_days" class="form-label">Number of Date for Transport</label>
|
||||
<input type="text" class="form-control" id="del_to_transport_days" name="del_to_transport_days">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_shipment_condition_category" class="form-label">Shipment Condition: Category</label>
|
||||
<input type="text" class="form-control" id="del_to_shipment_condition_category" name="del_to_shipment_condition_category">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Transport Service Exist</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="del_to_transport_service_exist[]" value="SUN" id="sun">
|
||||
<label class="form-check-label" for="sun">SUN</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="del_to_transport_service_exist[]" value="MON" id="mon">
|
||||
<label class="form-check-label" for="mon">MON</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="del_to_transport_service_exist[]" value="TUE" id="tue">
|
||||
<label class="form-check-label" for="tue">TUE</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="del_to_transport_service_exist[]" value="WED" id="wed">
|
||||
<label class="form-check-label" for="wed">WED</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="del_to_transport_service_exist[]" value="THR" id="thr">
|
||||
<label class="form-check-label" for="thr">THR</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="del_to_transport_service_exist[]" value="FRI" id="fri">
|
||||
<label class="form-check-label" for="fri">FRI</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="del_to_transport_service_exist[]" value="SAT" id="sat">
|
||||
<label class="form-check-label" for="sat">SAT</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="del_to_shipment_condition_place" class="form-label">Shipment Condition: Place</label>
|
||||
<input type="text" class="form-control" id="del_to_shipment_condition_place" name="del_to_shipment_condition_place">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 4: SOP -->
|
||||
<div class="form-section" id="step4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">SOP</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h5>Document Requirements</h5>
|
||||
<div class="mb-3">
|
||||
<label for="doc_req_do" class="form-label">D/O*</label>
|
||||
<input type="text" class="form-control" id="doc_req_do" name="doc_req_do">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="doc_req_packing_list" class="form-label">Packing List*</label>
|
||||
<input type="text" class="form-control" id="doc_req_packing_list" name="doc_req_packing_list">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="doc_req_invoice" class="form-label">Invoice*</label>
|
||||
<input type="text" class="form-control" id="doc_req_invoice" name="doc_req_invoice">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="doc_req_export_permit" class="form-label">Export Permit</label>
|
||||
<select class="form-select" id="doc_req_export_permit" name="doc_req_export_permit">
|
||||
<option value="">Choose one</option>
|
||||
<option value="YES">Yes</option>
|
||||
<option value="NO">No</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="doc_req_po_do_inv" class="form-label">1 PO/1 DO/1 INV</label>
|
||||
<select class="form-select" id="doc_req_po_do_inv" name="doc_req_po_do_inv">
|
||||
<option value="">Choose one</option>
|
||||
<option value="YES">Yes</option>
|
||||
<option value="NO">No</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="doc_req_do_inv" class="form-label">1 DO/1 INV</label>
|
||||
<select class="form-select" id="doc_req_do_inv" name="doc_req_do_inv">
|
||||
<option value="">Choose one</option>
|
||||
<option value="YES">Yes</option>
|
||||
<option value="NO">No</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="doc_req_others" class="form-label">Others</label>
|
||||
<textarea class="form-control" id="doc_req_others" name="doc_req_others" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h5>Packing Requirements</h5>
|
||||
<div class="mb-3">
|
||||
<label for="pack_req_one_line_carton" class="form-label">One Line One Carton</label>
|
||||
<select class="form-select" id="pack_req_one_line_carton" name="pack_req_one_line_carton">
|
||||
<option value="">Choose one</option>
|
||||
<option value="YES">Yes</option>
|
||||
<option value="NO">No</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="pack_req_one_item_carton" class="form-label">One Item One Carton</label>
|
||||
<select class="form-select" id="pack_req_one_item_carton" name="pack_req_one_item_carton">
|
||||
<option value="">Choose one</option>
|
||||
<option value="YES">Yes</option>
|
||||
<option value="NO">No</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="pack_req_one_item_pocket" class="form-label">One Item One Pocket</label>
|
||||
<select class="form-select" id="pack_req_one_item_pocket" name="pack_req_one_item_pocket">
|
||||
<option value="">Choose one</option>
|
||||
<option value="YES">Yes</option>
|
||||
<option value="NO">No</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="pack_req_thomson_label" class="form-label">Special Thomson Label</label>
|
||||
<input type="text" class="form-control" id="pack_req_thomson_label" name="pack_req_thomson_label">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="pack_req_contents_label" class="form-label">Special Contents Label</label>
|
||||
<input type="text" class="form-control" id="pack_req_contents_label" name="pack_req_contents_label">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="pack_req_delivery_schedule" class="form-label">Delivery schedule</label>
|
||||
<input type="text" class="form-control" id="pack_req_delivery_schedule" name="pack_req_delivery_schedule">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<h5>Forwarder Information</h5>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="forwarder_name" class="form-label">Forwarder Name</label>
|
||||
<input type="text" class="form-control" id="forwarder_name" name="forwarder_name">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="forwarder_code" class="form-label">Forwarder Code</label>
|
||||
<input type="text" class="form-control" id="forwarder_code" name="forwarder_code">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="forwarder_address" class="form-label">Forwarder Address</label>
|
||||
<textarea class="form-control" id="forwarder_address" name="forwarder_address" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="forwarder_contact_person" class="form-label">Contact Person</label>
|
||||
<input type="text" class="form-control" id="forwarder_contact_person" name="forwarder_contact_person">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="forwarder_phone" class="form-label">Phone</label>
|
||||
<input type="tel" class="form-control" id="forwarder_phone" name="forwarder_phone">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="forwarder_fax" class="form-label">Fax</label>
|
||||
<input type="tel" class="form-control" id="forwarder_fax" name="forwarder_fax">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="forwarder_delivery_method" class="form-label">Delivery Method</label>
|
||||
<select class="form-select" id="forwarder_delivery_method" name="forwarder_delivery_method">
|
||||
<option value="">Choose one</option>
|
||||
<option value="AIR">Air</option>
|
||||
<option value="SEA">Sea</option>
|
||||
<option value="LAND">Land</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="forwarder_delivery_timings" class="form-label">Delivery Timings</label>
|
||||
<input type="text" class="form-control" id="forwarder_delivery_timings" name="forwarder_delivery_timings">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="forwarder_delivery_requirements" class="form-label">Delivery Requirements</label>
|
||||
<input type="text" class="form-control" id="forwarder_delivery_requirements" name="forwarder_delivery_requirements">
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<h5>Special Instructions</h5>
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="special_instructions_shipping_mark" class="form-label">Shipping Mark</label>
|
||||
<select class="form-select" id="special_instructions_shipping_mark" name="special_instructions_shipping_mark">
|
||||
<option value="">Choose one</option>
|
||||
<option value="YES">Yes</option>
|
||||
<option value="NO">No</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label for="special_instructions_fax_documents" class="form-label">Fax Documents</label>
|
||||
<select class="form-select" id="special_instructions_fax_documents" name="special_instructions_fax_documents">
|
||||
<option value="">Choose one</option>
|
||||
<option value="YES">Yes</option>
|
||||
<option value="NO">No</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="special_instructions_details" class="form-label">Details</label>
|
||||
<input type="text" class="form-control" id="special_instructions_details" name="special_instructions_details">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="special_instructions_attention_to" class="form-label">Attention To</label>
|
||||
<input type="text" class="form-control" id="special_instructions_attention_to" name="special_instructions_attention_to">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="special_instructions_fax_number" class="form-label">Fax Number</label>
|
||||
<input type="text" class="form-control" id="special_instructions_fax_number" name="special_instructions_fax_number">
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="remarks" class="form-label">Remarks</label>
|
||||
<textarea class="form-control" id="remarks" name="remarks" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 5: Contacts -->
|
||||
<div class="form-section" id="step5">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
Contacts
|
||||
<button type="button" class="btn btn-sm btn-primary" id="addContact"><i class="bi bi-plus-circle"></i> Add Contact</button>
|
||||
</div>
|
||||
<div class="card-body" id="contactsContainer">
|
||||
<!-- Contact 1 -->
|
||||
<div class="contact-group border p-3 mb-3">
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="radio" name="contact[0][is_primary]" id="contact_0_is_primary" value="1" checked>
|
||||
<label class="form-check-label" for="contact_0_is_primary">Primary Contact</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3"><input type="text" name="contact[0][name]" class="form-control" placeholder="Name" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="email" name="contact[0][email]" class="form-control" placeholder="Email" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="tel" name="contact[0][phone]" class="form-control" placeholder="Phone"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 6: Addresses -->
|
||||
<div class="form-section" id="step6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
Addresses
|
||||
<button type="button" class="btn btn-sm btn-primary" id="addAddress"><i class="bi bi-plus-circle"></i> Add Address</button>
|
||||
</div>
|
||||
<div class="card-body" id="addressesContainer">
|
||||
<!-- Address 1 -->
|
||||
<div class="address-group border p-3 mb-3">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<select name="address[0][type]" class="form-select" required>
|
||||
<option value="BILLING">Billing</option>
|
||||
<option value="SHIPPING">Shipping</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3"><input type="text" name="address[0][line1]" class="form-control" placeholder="Address Line 1" required></div>
|
||||
<div class="mb-3"><input type="text" name="address[0][line2]" class="form-control" placeholder="Address Line 2"></div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[0][city]" class="form-control" placeholder="City" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[0][state]" class="form-control" placeholder="State/Province" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[0][postal_code]" class="form-control" placeholder="Postal Code" required></div>
|
||||
</div>
|
||||
<div class="mb-3"><input type="text" name="address[0][country]" class="form-control" placeholder="Country" required></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 7: Trade References -->
|
||||
<div class="form-section" id="step7">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
Trade References
|
||||
<button type="button" class="btn btn-sm btn-primary" id="addTradeReference"><i class="bi bi-plus-circle"></i> Add Trade Reference</button>
|
||||
</div>
|
||||
<div class="card-body" id="tradeReferencesContainer">
|
||||
<!-- Trade Reference 1 -->
|
||||
<div class="trade-reference-group border p-3 mb-3">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3"><input type="text" name="trade_reference[0][company_name]" class="form-control" placeholder="Company Name" required></div>
|
||||
<div class="col-md-6 mb-3"><input type="text" name="trade_reference[0][contact_person]" class="form-control" placeholder="Contact Person" required></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3"><input type="email" name="trade_reference[0][email]" class="form-control" placeholder="Email" required></div>
|
||||
<div class="col-md-6 mb-3"><input type="tel" name="trade_reference[0][phone]" class="form-control" placeholder="Phone"></div>
|
||||
</div>
|
||||
<div class="mb-3"><input type="text" name="trade_reference[0][address]" class="form-control" placeholder="Address" required></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 8: Bank Details -->
|
||||
<div class="form-section" id="step8">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Bank Details</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="bank_name" class="form-label">Bank Name</label>
|
||||
<input type="text" class="form-control" id="bank_name" name="bank_name">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="branch" class="form-label">Branch</label>
|
||||
<input type="text" class="form-control" id="branch" name="branch">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="bsb_number" class="form-label">BSB Number</label>
|
||||
<input type="text" class="form-control" id="bsb_number" name="bsb_number">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="account_number" class="form-label">Account Number</label>
|
||||
<input type="text" class="form-control" id="account_number" name="account_number">
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="account_name" class="form-label">Account Name</label>
|
||||
<input type="text" class="form-control" id="account_name" name="account_name">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 9: Declaration -->
|
||||
<div class="form-section" id="step9">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Declaration</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="declaration_text" class="form-label">Declaration</label>
|
||||
<textarea class="form-control" id="declaration_text" name="declaration_text" rows="5" required>I hereby declare that the information given in this application is true and correct to the best of my knowledge and belief.</textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="signature" class="form-label">Signature</label>
|
||||
<div class="border p-2">
|
||||
<canvas id="signature-pad" class="signature-pad" width=400 height=200></canvas>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary mt-2" id="clear-signature">Clear</button>
|
||||
<input type="hidden" name="signature" id="signature-data">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<button type="button" class="btn btn-secondary" id="prevBtn" style="display: none;">Previous</button>
|
||||
<button type="button" class="btn btn-primary" id="nextBtn">Next</button>
|
||||
<button type="submit" class="btn btn-success" id="submitBtn" style="display: none;">Submit Application</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.0.0/dist/signature_pad.umd.min.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
let currentStep = 1;
|
||||
const steps = document.querySelectorAll('.form-section');
|
||||
const prevBtn = document.getElementById('prevBtn');
|
||||
const nextBtn = document.getElementById('nextBtn');
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
|
||||
const signaturePad = new SignaturePad(document.getElementById('signature-pad'));
|
||||
|
||||
document.getElementById('clear-signature').addEventListener('click', function () {
|
||||
signaturePad.clear();
|
||||
});
|
||||
|
||||
document.getElementById('applicationForm').addEventListener('submit', function() {
|
||||
if (!signaturePad.isEmpty()) {
|
||||
document.getElementById('signature-data').value = signaturePad.toDataURL();
|
||||
}
|
||||
});
|
||||
|
||||
function showStep(step) {
|
||||
steps.forEach((s, index) => {
|
||||
s.classList.toggle('active', index + 1 === step);
|
||||
});
|
||||
prevBtn.style.display = step === 1 ? 'none' : 'inline-block';
|
||||
nextBtn.style.display = step === steps.length ? 'none' : 'inline-block';
|
||||
submitBtn.style.display = step === steps.length ? 'inline-block' : 'none';
|
||||
}
|
||||
|
||||
nextBtn.addEventListener('click', function() {
|
||||
if (currentStep < steps.length) {
|
||||
currentStep++;
|
||||
showStep(currentStep);
|
||||
}
|
||||
});
|
||||
|
||||
prevBtn.addEventListener('click', function() {
|
||||
if (currentStep > 1) {
|
||||
currentStep--;
|
||||
showStep(currentStep);
|
||||
}
|
||||
});
|
||||
|
||||
showStep(currentStep);
|
||||
|
||||
// Add Contact
|
||||
let contactIndex = 1;
|
||||
document.getElementById('addContact').addEventListener('click', function () {
|
||||
const container = document.getElementById('contactsContainer');
|
||||
const newContact = document.createElement('div');
|
||||
newContact.className = 'contact-group border p-3 mb-3';
|
||||
newContact.innerHTML = `
|
||||
<button type="button" class="btn-close float-end" aria-label="Close" onclick="this.parentElement.remove()"></button>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="radio" name="contact[${contactIndex}][is_primary]" id="contact_${contactIndex}_is_primary" value="1">
|
||||
<label class="form-check-label" for="contact_${contactIndex}_is_primary">Primary Contact</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3"><input type="text" name="contact[${contactIndex}][name]" class="form-control" placeholder="Name" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="email" name="contact[${contactIndex}][email]" class="form-control" placeholder="Email" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="tel" name="contact[${contactIndex}][phone]" class="form-control" placeholder="Phone"></div>
|
||||
</div>`;
|
||||
container.appendChild(newContact);
|
||||
contactIndex++;
|
||||
});
|
||||
|
||||
// Add Address
|
||||
let addressIndex = 1;
|
||||
document.getElementById('addAddress').addEventListener('click', function () {
|
||||
const container = document.getElementById('addressesContainer');
|
||||
const newAddress = document.createElement('div');
|
||||
newAddress.className = 'address-group border p-3 mb-3';
|
||||
newAddress.innerHTML = `
|
||||
<button type="button" class="btn-close float-end" aria-label="Close" onclick="this.parentElement.remove()"></button>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<select name="address[${addressIndex}][type]" class="form-select" required>
|
||||
<option value="BILLING">Billing</option>
|
||||
<option value="SHIPPING">Shipping</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3"><input type="text" name="address[${addressIndex}][line1]" class="form-control" placeholder="Address Line 1" required></div>
|
||||
<div class="mb-3"><input type="text" name="address[${addressIndex}][line2]" class="form-control" placeholder="Address Line 2"></div>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[${addressIndex}][city]" class="form-control" placeholder="City" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[${addressIndex}][state]" class="form-control" placeholder="State/Province" required></div>
|
||||
<div class="col-md-4 mb-3"><input type="text" name="address[${addressIndex}][postal_code]" class="form-control" placeholder="Postal Code" required></div>
|
||||
</div>
|
||||
<div class="mb-3"><input type="text" name="address[${addressIndex}][country]" class="form-control" placeholder="Country" required></div>`;
|
||||
container.appendChild(newAddress);
|
||||
addressIndex++;
|
||||
});
|
||||
|
||||
// Add Trade Reference
|
||||
let tradeReferenceIndex = 1;
|
||||
document.getElementById('addTradeReference').addEventListener('click', function () {
|
||||
const container = document.getElementById('tradeReferencesContainer');
|
||||
const newTradeReference = document.createElement('div');
|
||||
newTradeReference.className = 'trade-reference-group border p-3 mb-3';
|
||||
newTradeReference.innerHTML = `
|
||||
<button type="button" class="btn-close float-end" aria-label="Close" onclick="this.parentElement.remove()"></button>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3"><input type="text" name="trade_reference[${tradeReferenceIndex}][company_name]" class="form-control" placeholder="Company Name" required></div>
|
||||
<div class="col-md-6 mb-3"><input type="text" name="trade_reference[${tradeReferenceIndex}][contact_person]" class="form-control" placeholder="Contact Person" required></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3"><input type="email" name="trade_reference[${tradeReferenceIndex}][email]" class="form-control" placeholder="Email" required></div>
|
||||
<div class="col-md-6 mb-3"><input type="tel" name="trade_reference[${tradeReferenceIndex}][phone]" class="form-control" placeholder="Phone"></div>
|
||||
</div>
|
||||
<div class="mb-3"><input type="text" name="trade_reference[${tradeReferenceIndex}][address]" class="form-control" placeholder="Address" required></div>`;
|
||||
container.appendChild(newTradeReference);
|
||||
tradeReferenceIndex++;
|
||||
});
|
||||
|
||||
// Uncheck other radio buttons when one is selected
|
||||
document.getElementById('contactsContainer').addEventListener('change', function(e) {
|
||||
if (e.target.type === 'radio' && e.target.checked) {
|
||||
document.querySelectorAll('input[type="radio"][name^="contact"]').forEach(radio => {
|
||||
if (radio !== e.target) {
|
||||
radio.checked = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
7
permissions.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
function has_permission($permission) {
|
||||
if (isset($_SESSION['user']['permissions']) && in_array($permission, $_SESSION['user']['permissions'])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
129
process_approval.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'includes/auth_helpers.php';
|
||||
require_once 'db/config.php';
|
||||
require_once 'mail/MailService.php';
|
||||
|
||||
redirect_if_not_authenticated();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
exit('Method Not Allowed');
|
||||
}
|
||||
|
||||
$application_id = $_POST['application_id'] ?? null;
|
||||
$action = $_POST['action'] ?? null;
|
||||
|
||||
if (!$application_id || !$action) {
|
||||
header('Location: view_applications.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
|
||||
// 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->execute([$role_name]);
|
||||
return $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
}
|
||||
|
||||
// Fetch application
|
||||
$stmt = $pdo->prepare('SELECT * FROM customer_applications WHERE id = ?');
|
||||
$stmt->execute([$application_id]);
|
||||
$application = $stmt->fetch();
|
||||
|
||||
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();
|
||||
|
||||
try {
|
||||
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();
|
||||
|
||||
if ($next_approver_role) {
|
||||
// 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.'];
|
||||
|
||||
// Notify next approvers
|
||||
$next_approver_emails = get_user_emails_by_role($next_approver_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 = "
|
||||
<p>A new credit application requires your approval.</p>
|
||||
<p><strong>Customer Name:</strong> {$application['company_name']}</p>
|
||||
<p><strong>Sales Rep:</strong> {$sales_rep_name}</p>
|
||||
<p><strong>Credit Amount:</strong> $" . number_format($credit_amount, 2) . "</p>
|
||||
<p><strong>Submission Date:</strong> {$submission_date}</p>
|
||||
<p><a href='http://{$_SERVER['HTTP_HOST']}/view_application.php?id={$application_id}' style='display: inline-block; padding: 10px 20px; background-color: #007bff; color: #fff; text-decoration: none;'>View Application</a></p>
|
||||
";
|
||||
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.'];
|
||||
|
||||
// Notify applicant
|
||||
if ($applicant_email) {
|
||||
$subject = 'Your Application has been Approved: ' . $application['application_id'];
|
||||
$body = "<p>Congratulations! Your customer application ({$application['application_id']}) has been approved.</p>";
|
||||
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.'];
|
||||
|
||||
// Notify applicant
|
||||
if ($applicant_email) {
|
||||
$subject = 'Your Application has been Rejected: ' . $application['application_id'];
|
||||
$body = "<p>We regret to inform you that your customer application ({$application['application_id']}) has been rejected.</p>";
|
||||
MailService::sendMail($applicant_email, $subject, $body);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log('Approval processing failed: ' . $e->getMessage());
|
||||
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'An error occurred. Please try again.'];
|
||||
}
|
||||
|
||||
header('Location: view_application.php?id=' . $application_id);
|
||||
exit();
|
||||
127
profile.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'includes/auth_helpers.php';
|
||||
|
||||
// Protect route: check if user is logged in
|
||||
if (!isset($_SESSION['user'])) {
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$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'] ?? '';
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>User Profile - <?php echo htmlspecialchars($projectName); ?></title>
|
||||
<meta name="description" content="<?php echo htmlspecialchars($projectDescription); ?>">
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="<?php echo htmlspecialchars($projectName); ?>">
|
||||
<meta property="og:description" content="<?php echo htmlspecialchars($projectDescription); ?>">
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<meta property="og:image" content="<?php echo htmlspecialchars($projectImageUrl); ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:title" content="<?php echo htmlspecialchars($projectName); ?>">
|
||||
<meta property="twitter:description" content="<?php echo htmlspecialchars($projectDescription); ?>">
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<meta property="twitter:image" content="<?php echo htmlspecialchars($projectImageUrl); ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="index.php"><i class="bi bi-person-vcard"></i> <?php echo htmlspecialchars($projectName); ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mainNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="mainNav">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Dashboard</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle active" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-person-circle"></i> <?php echo htmlspecialchars($user['username']); ?>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="profile.php">Profile</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" href="logout.php"><i class="bi bi-box-arrow-right"></i> Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="container mt-4">
|
||||
<div class="row">
|
||||
<div class="col-md-6 offset-md-3">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title"><i class="bi bi-person-badge"></i> User Profile</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Username:</strong> <?php echo htmlspecialchars($user['username']); ?></p>
|
||||
<p><strong>Role:</strong> <?php echo htmlspecialchars(ucfirst($user['role'])); ?></p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h5><i class="bi bi-key"></i> Change Password</h5>
|
||||
|
||||
<?php if (isset($_SESSION['flash_message'])): ?>
|
||||
<div class="alert alert-<?php echo $_SESSION['flash_message']['type']; ?> alert-dismissible fade show" role="alert">
|
||||
<?php echo $_SESSION['flash_message']['message']; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php unset($_SESSION['flash_message']); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="update_profile.php" method="POST">
|
||||
<div class="mb-3">
|
||||
<label for="current_password" class="form-label">Current Password</label>
|
||||
<input type="password" class="form-control" id="current_password" name="current_password" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="new_password" class="form-label">New Password</label>
|
||||
<input type="password" class="form-control" id="new_password" name="new_password" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="confirm_new_password" class="form-label">Confirm New Password</label>
|
||||
<input type="password" class="form-control" id="confirm_new_password" name="confirm_new_password" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-save"></i> Update Password</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
221
submit_application.php
Normal file
@ -0,0 +1,221 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
exit('Method Not Allowed');
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['user'])) {
|
||||
http_response_code(403);
|
||||
exit('Unauthorized');
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
|
||||
try {
|
||||
// Get the role ID for the first approval level
|
||||
$stmt_role = $pdo->prepare("SELECT id FROM roles WHERE name = 'Approver Level 1'");
|
||||
$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 = $db->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
|
||||
]);
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
// Redirect to dashboard with success message
|
||||
$_SESSION['flash_message'] = [
|
||||
'type' => 'success',
|
||||
'message' => 'Customer application (' . $application_id . ') submitted successfully!'
|
||||
];
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
|
||||
} 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()
|
||||
];
|
||||
header('Location: new_application.php');
|
||||
exit();
|
||||
}
|
||||
179
update_application.php
Normal file
@ -0,0 +1,179 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'includes/auth_helpers.php';
|
||||
redirect_if_not_authenticated();
|
||||
redirect_if_no_permission('edit_application');
|
||||
|
||||
require_once 'db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$customer_id = $_POST['customer_id'] ?? null;
|
||||
if (!$customer_id) {
|
||||
die("Invalid request.");
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
|
||||
// Handle File Upload
|
||||
if (isset($_POST['upload_file'])) {
|
||||
if (isset($_FILES['file_upload']) && $_FILES['file_upload']['error'] === UPLOAD_ERR_OK) {
|
||||
$file_tmp_path = $_FILES['file_upload']['tmp_name'];
|
||||
$file_name = basename($_FILES['file_upload']['name']);
|
||||
|
||||
// Sanitize filename
|
||||
$new_file_name = preg_replace('/[^a-zA-Z0-9-_. ]/', '', $file_name);
|
||||
$unique_file_name = time() . '-' . $new_file_name;
|
||||
$dest_path = 'uploads/' . $unique_file_name;
|
||||
|
||||
if (move_uploaded_file($file_tmp_path, $dest_path)) {
|
||||
try {
|
||||
$sql = "INSERT INTO application_files (customer_application_id, filename, filepath) VALUES (?, ?, ?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$customer_id, $file_name, $unique_file_name]);
|
||||
$_SESSION['success_message'] = "File uploaded successfully.";
|
||||
} catch (PDOException $e) {
|
||||
$_SESSION['error_message'] = "Error saving file info: " . $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
$_SESSION['error_message'] = "Error moving uploaded file.";
|
||||
}
|
||||
} else {
|
||||
$_SESSION['error_message'] = "Error uploading file: " . $_FILES['file_upload']['error'];
|
||||
}
|
||||
header("Location: edit_application.php?id=" . $customer_id);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Handle Form Submission
|
||||
if (isset($_POST['save_changes'])) {
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// 1. Update Customer Table
|
||||
$sql = "UPDATE customer_applications SET
|
||||
company_name = ?,
|
||||
company_website = ?,
|
||||
company_phone = ?,
|
||||
sales_owner = ?,
|
||||
payment_terms = ?,
|
||||
tags = ?,
|
||||
notes = ?
|
||||
WHERE id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
$_POST['company_name'],
|
||||
$_POST['company_website'],
|
||||
$_POST['company_phone'],
|
||||
$_POST['sales_owner'],
|
||||
$_POST['payment_terms'],
|
||||
$_POST['tags'],
|
||||
$_POST['notes'],
|
||||
$customer_id
|
||||
]);
|
||||
|
||||
// 2. Process Contacts
|
||||
$submitted_contact_ids = [];
|
||||
if (isset($_POST['contact']) && is_array($_POST['contact'])) {
|
||||
// Reset primary contact
|
||||
$reset_primary_stmt = $pdo->prepare("UPDATE customer_contacts SET is_primary = 0 WHERE customer_application_id = ?");
|
||||
$reset_primary_stmt->execute([$customer_id]);
|
||||
|
||||
foreach ($_POST['contact'] as $index => $contact_data) {
|
||||
$contact_id = $contact_data['id'] ?? null;
|
||||
$is_primary = (isset($contact_data['is_primary']) && $contact_data['is_primary'] == '1') ? 1 : 0;
|
||||
|
||||
if ($contact_id) { // Existing contact
|
||||
$sql = "UPDATE customer_contacts SET name = ?, email = ?, phone = ?, is_primary = ? WHERE id = ? AND customer_application_id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$contact_data['name'], $contact_data['email'], $contact_data['phone'], $is_primary, $contact_id, $customer_id]);
|
||||
$submitted_contact_ids[] = $contact_id;
|
||||
} else { // New contact
|
||||
$sql = "INSERT INTO customer_contacts (customer_application_id, name, email, phone, is_primary) VALUES (?, ?, ?, ?, ?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$customer_id, $contact_data['name'], $contact_data['email'], $contact_data['phone'], $is_primary]);
|
||||
$submitted_contact_ids[] = $pdo->lastInsertId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Delete Removed Contacts
|
||||
$stmt = $pdo->prepare("SELECT id FROM customer_contacts WHERE customer_application_id = ?");
|
||||
$stmt->execute([$customer_id]);
|
||||
$existing_contact_ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
$contacts_to_delete = array_diff($existing_contact_ids, $submitted_contact_ids);
|
||||
|
||||
if (!empty($contacts_to_delete)) {
|
||||
$sql = "DELETE FROM customer_contacts WHERE id IN (" . implode(',', array_fill(0, count($contacts_to_delete), '?')) . ") AND customer_application_id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$params = array_merge(array_values($contacts_to_delete), [$customer_id]);
|
||||
$stmt->execute($params);
|
||||
}
|
||||
|
||||
// 4. Process Addresses
|
||||
$submitted_address_ids = [];
|
||||
if (isset($_POST['address']) && is_array($_POST['address'])) {
|
||||
foreach ($_POST['address'] as $address_data) {
|
||||
$address_id = $address_data['id'] ?? null;
|
||||
|
||||
if ($address_id) { // Existing address
|
||||
$sql = "UPDATE customer_addresses SET address_type = ?, address_line_1 = ?, address_line_2 = ?, city = ?, state = ?, postal_code = ?, country = ? WHERE id = ? AND customer_application_id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$address_data['type'], $address_data['line1'], $address_data['line2'], $address_data['city'], $address_data['state'], $address_data['postal_code'], $address_data['country'], $address_id, $customer_id]);
|
||||
$submitted_address_ids[] = $address_id;
|
||||
} else { // New address
|
||||
$sql = "INSERT INTO customer_addresses (customer_application_id, address_type, address_line_1, address_line_2, city, state, postal_code, country) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$customer_id, $address_data['type'], $address_data['line1'], $address_data['line2'], $address_data['city'], $address_data['state'], $address_data['postal_code'], $address_data['country']]);
|
||||
$submitted_address_ids[] = $pdo->lastInsertId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Delete Removed Addresses
|
||||
$stmt = $pdo->prepare("SELECT id FROM customer_addresses WHERE customer_application_id = ?");
|
||||
$stmt->execute([$customer_id]);
|
||||
$existing_address_ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
$addresses_to_delete = array_diff($existing_address_ids, $submitted_address_ids);
|
||||
|
||||
if (!empty($addresses_to_delete)) {
|
||||
$sql = "DELETE FROM customer_addresses WHERE id IN (" . implode(',', array_fill(0, count($addresses_to_delete), '?')) . ") AND customer_application_id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$params = array_merge(array_values($addresses_to_delete), [$customer_id]);
|
||||
$stmt->execute($params);
|
||||
}
|
||||
|
||||
// Check if the application was reverted and resubmit it
|
||||
$stmt_status = $pdo->prepare("SELECT status FROM customer_applications WHERE id = ?");
|
||||
$stmt_status->execute([$customer_id]);
|
||||
$current_status = $stmt_status->fetchColumn();
|
||||
|
||||
if ($current_status === 'REVERTED') {
|
||||
$stmt_resubmit = $pdo->prepare("UPDATE customer_applications SET status = 'pending_approval' WHERE id = ?");
|
||||
$stmt_resubmit->execute([$customer_id]);
|
||||
$_SESSION['message'] = "Application resubmitted for approval.";
|
||||
$_SESSION['message_type'] = 'success';
|
||||
} else {
|
||||
$_SESSION['message'] = "Application #{$customer_id} updated successfully.";
|
||||
$_SESSION['message_type'] = 'success';
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
} catch (Exception $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
$_SESSION['message'] = "Error updating application: " . $e->getMessage();
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
}
|
||||
|
||||
header("Location: view_application.php?id=" . $customer_id);
|
||||
exit();
|
||||
}
|
||||
|
||||
header("Location: index.php");
|
||||
exit();
|
||||
67
update_profile.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'includes/auth_helpers.php';
|
||||
|
||||
// Protect route: check if user is logged in
|
||||
if (!isset($_SESSION['user'])) {
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$current_password = $_POST['current_password'] ?? '';
|
||||
$new_password = $_POST['new_password'] ?? '';
|
||||
$confirm_new_password = $_POST['confirm_new_password'] ?? '';
|
||||
|
||||
// 1. Validate inputs
|
||||
if (empty($current_password) || empty($new_password) || empty($confirm_new_password)) {
|
||||
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'All fields are required.'];
|
||||
header('Location: profile.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($new_password !== $confirm_new_password) {
|
||||
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'New passwords do not match.'];
|
||||
header('Location: profile.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// 2. Fetch current user from DB to verify current password
|
||||
$stmt = $pdo->prepare("SELECT password FROM users WHERE id = ?");
|
||||
$stmt->execute([$_SESSION['user']['id']]);
|
||||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$user || !password_verify($current_password, $user['password'])) {
|
||||
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'Incorrect current password.'];
|
||||
header('Location: profile.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
// 3. Hash new password
|
||||
$new_password_hash = password_hash($new_password, PASSWORD_DEFAULT);
|
||||
|
||||
// 4. Update password in the database
|
||||
$stmt = $pdo->prepare("UPDATE users SET password = ? WHERE id = ?");
|
||||
$stmt->execute([$new_password_hash, $_SESSION['user']['id']]);
|
||||
|
||||
$_SESSION['flash_message'] = ['type' => 'success', 'message' => 'Password updated successfully.'];
|
||||
header('Location: profile.php');
|
||||
exit();
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// Log error and show a generic message
|
||||
error_log("Password update failed: " . $e->getMessage());
|
||||
$_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'An error occurred. Please try again.'];
|
||||
header('Location: profile.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
} else {
|
||||
// Redirect if not a POST request
|
||||
header('Location: profile.php');
|
||||
exit();
|
||||
}
|
||||
105
update_status.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'includes/auth_helpers.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
redirect_if_not_authenticated();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
exit('Method Not Allowed');
|
||||
}
|
||||
|
||||
$application_id = $_POST['application_id'] ?? null;
|
||||
$new_status = $_POST['status'] ?? null;
|
||||
$comments = $_POST['comments'] ?? '';
|
||||
|
||||
if (!$application_id || !in_array($new_status, ['approved', 'rejected', 'reverted'])) {
|
||||
$_SESSION['message'] = 'Invalid request.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
|
||||
try {
|
||||
// Get current application details
|
||||
$stmt_app = $pdo->prepare("SELECT approval_level, current_approver_role_id FROM customer_applications WHERE id = ?");
|
||||
$stmt_app->execute([$application_id]);
|
||||
$application = $stmt_app->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$application) {
|
||||
$_SESSION['message'] = 'Application not found.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$current_level = $application['approval_level'];
|
||||
$current_approver_role_id = $application['current_approver_role_id'];
|
||||
$user_role_id = $_SESSION['user']['role_id'];
|
||||
|
||||
// Check if the user has permission to approve at this level
|
||||
if ($user_role_id != $current_approver_role_id) {
|
||||
$_SESSION['message'] = 'You do not have permission to approve this application at the current level.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: view_application.php?id=' . $application_id);
|
||||
exit();
|
||||
}
|
||||
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Insert into application_approvals
|
||||
$stmt_approval = $pdo->prepare(
|
||||
'INSERT INTO application_approvals (application_id, approver_id, approval_level, status, comments) VALUES (?, ?, ?, ?, ?)'
|
||||
);
|
||||
$stmt_approval->execute([$application_id, $_SESSION['user']['id'], $current_level, $new_status, $comments]);
|
||||
|
||||
if ($new_status === 'approved') {
|
||||
$next_level = $current_level + 1;
|
||||
if ($next_level <= 7) {
|
||||
// Get the role ID for the next approval level
|
||||
$stmt_role = $pdo->prepare("SELECT id FROM roles WHERE name = ?");
|
||||
$stmt_role->execute(['Approver Level ' . $next_level]);
|
||||
$next_approver_role = $stmt_role->fetch(PDO::FETCH_ASSOC);
|
||||
$next_approver_role_id = $next_approver_role ? $next_approver_role['id'] : null;
|
||||
|
||||
$stmt_update = $pdo->prepare(
|
||||
'UPDATE customer_applications SET approval_level = ?, current_approver_role_id = ? WHERE id = ?'
|
||||
);
|
||||
$stmt_update->execute([$next_level, $next_approver_role_id, $application_id]);
|
||||
$_SESSION['message'] = "Application approved and moved to the next level.";
|
||||
|
||||
} else {
|
||||
$stmt_update = $pdo->prepare(
|
||||
"UPDATE customer_applications SET status = 'APPROVED', approval_level = 7, current_approver_role_id = NULL WHERE id = ?"
|
||||
);
|
||||
$stmt_update->execute([$application_id]);
|
||||
$_SESSION['message'] = "Application approved.";
|
||||
}
|
||||
} elseif ($new_status === 'reverted') { // Reverted
|
||||
$stmt_update = $pdo->prepare(
|
||||
"UPDATE customer_applications SET status = 'REVERTED' WHERE id = ?"
|
||||
);
|
||||
$stmt_update->execute([$application_id]);
|
||||
$_SESSION['message'] = "Application reverted to the applicant for amendments.";
|
||||
} else { // Rejected
|
||||
$stmt_update = $pdo->prepare(
|
||||
"UPDATE customer_applications SET status = 'REJECTED', current_approver_role_id = NULL WHERE id = ?"
|
||||
);
|
||||
$stmt_update->execute([$application_id]);
|
||||
$_SESSION['message'] = "Application rejected.";
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
$_SESSION['message_type'] = 'success';
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
$_SESSION['message'] = 'Database error: ' . $e->getMessage();
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
}
|
||||
|
||||
header('Location: view_application.php?id=' . $application_id);
|
||||
exit();
|
||||
72
upload_file.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'includes/auth_helpers.php';
|
||||
redirect_if_not_authenticated();
|
||||
redirect_if_no_permission('upload_files');
|
||||
|
||||
require_once 'db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$application_id = $_POST['application_id'] ?? null;
|
||||
|
||||
if (!$application_id) {
|
||||
$_SESSION['message'] = 'Invalid application ID.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
if (isset($_FILES['document']) && $_FILES['document']['error'] === UPLOAD_ERR_OK) {
|
||||
$file = $_FILES['document'];
|
||||
$original_filename = basename($file['name']);
|
||||
$stored_filename = uniqid('', true) . '-' . $original_filename;
|
||||
$upload_dir = __DIR__ . '/uploads/';
|
||||
$upload_path = $upload_dir . $stored_filename;
|
||||
|
||||
// Basic validation (you can add more)
|
||||
$allowed_types = ['application/pdf', 'image/jpeg', 'image/png', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
|
||||
if (!in_array($file['type'], $allowed_types)) {
|
||||
$_SESSION['message'] = 'Invalid file type. Allowed types: PDF, JPG, PNG, DOC, DOCX.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: view_application.php?id=' . $application_id);
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($file['size'] > 5 * 1024 * 1024) { // 5MB limit
|
||||
$_SESSION['message'] = 'File is too large. Maximum size is 5MB.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: view_application.php?id=' . $application_id);
|
||||
exit();
|
||||
}
|
||||
|
||||
if (move_uploaded_file($file['tmp_name'], $upload_path)) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("INSERT INTO application_files (application_id, original_filename, stored_filename) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$application_id, $original_filename, $stored_filename]);
|
||||
|
||||
$_SESSION['message'] = 'File uploaded successfully.';
|
||||
$_SESSION['message_type'] = 'success';
|
||||
} catch (PDOException $e) {
|
||||
// In a real app, log this error
|
||||
$_SESSION['message'] = 'Database error while saving file information.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
// Optionally, delete the uploaded file if DB insert fails
|
||||
unlink($upload_path);
|
||||
}
|
||||
} else {
|
||||
$_SESSION['message'] = 'Failed to move uploaded file.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
}
|
||||
} else {
|
||||
$_SESSION['message'] = 'File upload error. Please try again.';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
}
|
||||
|
||||
header('Location: view_application.php?id=' . $application_id);
|
||||
exit();
|
||||
|
||||
} else {
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
}
|
||||
1
uploads/.htaccess
Normal file
@ -0,0 +1 @@
|
||||
deny from all
|
||||
408
view_application.php
Normal file
@ -0,0 +1,408 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'includes/auth_helpers.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
redirect_if_not_authenticated();
|
||||
|
||||
if (!isset($_GET['id']) || empty($_GET['id'])) {
|
||||
header('Location: view_applications.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$application_id = $_GET['id'];
|
||||
$pdo = db();
|
||||
|
||||
// Fetch application details
|
||||
$stmt = $pdo->prepare('SELECT * FROM customer_applications WHERE id = ?');
|
||||
$stmt->execute([$application_id]);
|
||||
$application = $stmt->fetch();
|
||||
|
||||
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 addresses
|
||||
$stmt = $pdo->prepare('SELECT * FROM customer_addresses WHERE customer_application_id = ?');
|
||||
$stmt->execute([$application_id]);
|
||||
$addresses = $stmt->fetchAll();
|
||||
|
||||
// Fetch trade references
|
||||
$stmt = $pdo->prepare('SELECT * FROM customer_trade_references WHERE customer_application_id = ?');
|
||||
$stmt->execute([$application_id]);
|
||||
$trade_references = $stmt->fetchAll();
|
||||
|
||||
// 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();
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>View Application - <?= htmlspecialchars($application['application_id']) ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Customer Master</a>
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Dashboard</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="view_applications.php">View Applications</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="logout.php">Logout</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container mt-4">
|
||||
<h2>Application Details: <?= htmlspecialchars($application['application_id']) ?></h2>
|
||||
|
||||
<!-- Company Details -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Company Details</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Company Name:</strong> <?= htmlspecialchars($application['company_name']) ?></p>
|
||||
<p><strong>Company Website:</strong> <a href="<?= htmlspecialchars($application['company_website']) ?>" target="_blank"><?= htmlspecialchars($application['company_website']) ?></a></p>
|
||||
<p><strong>Company Phone:</strong> <?= htmlspecialchars($application['company_phone']) ?></p>
|
||||
<p><strong>Sales Owner:</strong> <?= htmlspecialchars($application['sales_owner']) ?></p>
|
||||
<p><strong>Payment Terms:</strong> <?= htmlspecialchars($application['payment_terms']) ?></p>
|
||||
<p><strong>Tags:</strong> <?= htmlspecialchars($application['tags']) ?></p>
|
||||
<p><strong>Notes:</strong> <?= nl2br(htmlspecialchars($application['notes'])) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Financial & Credit Details -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Financial & Credit Details</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Major Product:</strong> <?= htmlspecialchars($application['major_product']) ?></p>
|
||||
<p><strong>Capital:</strong> <?= htmlspecialchars($application['capital']) ?> <?= htmlspecialchars($application['capital_currency']) ?></p>
|
||||
<p><strong>Main Shareholders:</strong> <?= htmlspecialchars($application['main_shareholders']) ?></p>
|
||||
<p><strong>Number of Employees:</strong> <?= htmlspecialchars($application['num_employees']) ?></p>
|
||||
<p><strong>Payment Terms AR:</strong> <?= htmlspecialchars($application['payment_terms_ar']) ?></p>
|
||||
<hr>
|
||||
<h6>P/L Information</h6>
|
||||
<p><strong>Year:</strong> <?= htmlspecialchars($application['pl_year']) ?></p>
|
||||
<p><strong>Net Sales:</strong> <?= htmlspecialchars($application['net_sales']) ?></p>
|
||||
<p><strong>Net Income Margin:</strong> <?= htmlspecialchars($application['net_income_margin']) ?></p>
|
||||
<p><strong>Net Income Margin Ratio:</strong> <?= htmlspecialchars($application['net_income_margin_ratio']) ?>%</p>
|
||||
<hr>
|
||||
<h6>ROHM Sales Target (KUS$)</h6>
|
||||
<p><strong>This Year:</strong> <?= htmlspecialchars($application['sales_target_this_year']) ?></p>
|
||||
<p><strong>Next Year:</strong> <?= htmlspecialchars($application['sales_target_next_year']) ?></p>
|
||||
<p><strong>After the Next:</strong> <?= htmlspecialchars($application['sales_target_after_next']) ?></p>
|
||||
<hr>
|
||||
<h6>Credit Information</h6>
|
||||
<p><strong>Rank:</strong> <?= htmlspecialchars($application['credit_rank']) ?></p>
|
||||
<p><strong>Limit:</strong> <?= htmlspecialchars($application['credit_limit']) ?> KUS$</p>
|
||||
<hr>
|
||||
<h6>Credit Research</h6>
|
||||
<p><strong>Status:</strong> <?= htmlspecialchars($application['credit_research_status']) ?></p>
|
||||
<p><strong>Reason:</strong> <?= htmlspecialchars($application['credit_research_reason']) ?></p>
|
||||
<hr>
|
||||
<p><strong>Tax Rate/Area (GST TYPE):</strong> <?= htmlspecialchars($application['tax_rate_area']) ?></p>
|
||||
<p><strong>Billing Type:</strong> <?= htmlspecialchars($application['billing_type']) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Del-To Informations -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Del-To Informations</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Del-To Code:</strong> <?= htmlspecialchars($application['del_to_code']) ?></p>
|
||||
<p><strong>Abbreviation of Delivery-To:</strong> <?= htmlspecialchars($application['delivery_abbreviation']) ?></p>
|
||||
<p><strong>Customer Name:</strong> <?= htmlspecialchars($application['del_to_customer_name']) ?></p>
|
||||
<p><strong>Address:</strong><br>
|
||||
<?= htmlspecialchars($application['del_to_address_1']) ?><br>
|
||||
<?php if(!empty($application['del_to_address_2'])): ?>
|
||||
<?= htmlspecialchars($application['del_to_address_2']) ?><br>
|
||||
<?php endif; ?>
|
||||
<?php if(!empty($application['del_to_address_3'])): ?>
|
||||
<?= htmlspecialchars($application['del_to_address_3']) ?><br>
|
||||
<?php endif; ?>
|
||||
<?php if(!empty($application['del_to_address_4'])): ?>
|
||||
<?= htmlspecialchars($application['del_to_address_4']) ?><br>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<p><strong>Postcode (Zip Code):</strong> <?= htmlspecialchars($application['del_to_postcode']) ?></p>
|
||||
<p><strong>Phone Number:</strong> <?= htmlspecialchars($application['del_to_phone']) ?></p>
|
||||
<p><strong>Area Code:</strong> <?= htmlspecialchars($application['del_to_area_code']) ?></p>
|
||||
<p><strong>Transportation Code:</strong> <?= htmlspecialchars($application['del_to_transportation_code']) ?></p>
|
||||
<p><strong>Stock Point Code:</strong> <?= htmlspecialchars($application['del_to_stock_point_code']) ?></p>
|
||||
<p><strong>Recipient Section:</strong> <?= htmlspecialchars($application['del_to_recipient_section']) ?></p>
|
||||
<p><strong>Country Code:</strong> <?= htmlspecialchars($application['del_to_country_code']) ?></p>
|
||||
<p><strong>Shipment Flag:</strong> <?= htmlspecialchars($application['del_to_shipment_flag']) ?></p>
|
||||
<p><strong>Number of Date for Transport:</strong> <?= htmlspecialchars($application['del_to_transport_days']) ?></p>
|
||||
<p><strong>Shipment Condition: Category:</strong> <?= htmlspecialchars($application['del_to_shipment_condition_category']) ?></p>
|
||||
<p><strong>Transport Service Exist:</strong> <?= htmlspecialchars($application['del_to_transport_service_exist']) ?></p>
|
||||
<p><strong>Shipment Condition: Place:</strong> <?= htmlspecialchars($application['del_to_shipment_condition_place']) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SOP -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">SOP</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h5>Document Requirements</h5>
|
||||
<p><strong>D/O*:</strong> <?= htmlspecialchars($application['doc_req_do']) ?></p>
|
||||
<p><strong>Packing List*:</strong> <?= htmlspecialchars($application['doc_req_packing_list']) ?></p>
|
||||
<p><strong>Invoice*:</strong> <?= htmlspecialchars($application['doc_req_invoice']) ?></p>
|
||||
<p><strong>Export Permit:</strong> <?= htmlspecialchars($application['doc_req_export_permit']) ?></p>
|
||||
<p><strong>1 PO/1 DO/1 INV:</strong> <?= htmlspecialchars($application['doc_req_po_do_inv']) ?></p>
|
||||
<p><strong>1 DO/1 INV:</strong> <?= htmlspecialchars($application['doc_req_do_inv']) ?></p>
|
||||
<p><strong>Others:</strong> <?= nl2br(htmlspecialchars($application['doc_req_others'])) ?></p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h5>Packing Requirements</h5>
|
||||
<p><strong>One Line One Carton:</strong> <?= htmlspecialchars($application['pack_req_one_line_carton']) ?></p>
|
||||
<p><strong>One Item One Carton:</strong> <?= htmlspecialchars($application['pack_req_one_item_carton']) ?></p>
|
||||
<p><strong>One Item One Pocket:</strong> <?= htmlspecialchars($application['pack_req_one_item_pocket']) ?></p>
|
||||
<p><strong>Special Thomson Label:</strong> <?= htmlspecialchars($application['pack_req_thomson_label']) ?></p>
|
||||
<p><strong>Special Contents Label:</strong> <?= htmlspecialchars($application['pack_req_contents_label']) ?></p>
|
||||
<p><strong>Delivery schedule:</strong> <?= htmlspecialchars($application['pack_req_delivery_schedule']) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<h5>Forwarder Information</h5>
|
||||
<p><strong>Forwarder Name:</strong> <?= htmlspecialchars($application['forwarder_name']) ?></p>
|
||||
<p><strong>Forwarder Code:</strong> <?= htmlspecialchars($application['forwarder_code']) ?></p>
|
||||
<p><strong>Forwarder Address:</strong> <?= nl2br(htmlspecialchars($application['forwarder_address'])) ?></p>
|
||||
<p><strong>Contact Person:</strong> <?= htmlspecialchars($application['forwarder_contact_person']) ?></p>
|
||||
<p><strong>Phone:</strong> <?= htmlspecialchars($application['forwarder_phone']) ?></p>
|
||||
<p><strong>Fax:</strong> <?= htmlspecialchars($application['forwarder_fax']) ?></p>
|
||||
<p><strong>Delivery Method:</strong> <?= htmlspecialchars($application['forwarder_delivery_method']) ?></p>
|
||||
<p><strong>Delivery Timings:</strong> <?= htmlspecialchars($application['forwarder_delivery_timings']) ?></p>
|
||||
<p><strong>Delivery Requirements:</strong> <?= nl2br(htmlspecialchars($application['forwarder_delivery_requirements'])) ?></p>
|
||||
<hr>
|
||||
<h5>Special Instructions</h5>
|
||||
<p><strong>Shipping Mark:</strong> <?= htmlspecialchars($application['special_instructions_shipping_mark']) ?></p>
|
||||
<p><strong>Fax Documents:</strong> <?= htmlspecialchars($application['special_instructions_fax_documents']) ?></p>
|
||||
<p><strong>Details:</strong> <?= htmlspecialchars($application['special_instructions_details']) ?></p>
|
||||
<p><strong>Attention To:</strong> <?= htmlspecialchars($application['special_instructions_attention_to']) ?></p>
|
||||
<p><strong>Fax Number:</strong> <?= htmlspecialchars($application['special_instructions_fax_number']) ?></p>
|
||||
<p><strong>Remarks:</strong> <?= nl2br(htmlspecialchars($application['remarks'])) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contacts -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Contacts</div>
|
||||
<div class="card-body">
|
||||
<?php foreach ($contacts as $contact): ?>
|
||||
<div class="mb-3 border-bottom pb-3">
|
||||
<p><strong>Name:</strong> <?= htmlspecialchars($contact['name']) ?> <?= $contact['is_primary'] ? '(Primary)' : '' ?></p>
|
||||
<p><strong>Email:</strong> <?= htmlspecialchars($contact['email']) ?></p>
|
||||
<p><strong>Phone:</strong> <?= htmlspecialchars($contact['phone']) ?></p>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Addresses -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Addresses</div>
|
||||
<div class="card-body">
|
||||
<?php foreach ($addresses as $address): ?>
|
||||
<div class="mb-3 border-bottom pb-3">
|
||||
<p><strong>Type:</strong> <?= htmlspecialchars($address['address_type']) ?></p>
|
||||
<p><strong>Address:</strong><br>
|
||||
<?= htmlspecialchars($address['address_line_1']) ?><br>
|
||||
<?php if(!empty($address['address_line_2'])): ?>
|
||||
<?= htmlspecialchars($address['address_line_2']) ?><br>
|
||||
<?php endif; ?>
|
||||
<?= htmlspecialchars($address['city']) ?>, <?= htmlspecialchars($address['state']) ?> <?= htmlspecialchars($address['postal_code']) ?><br>
|
||||
<?= htmlspecialchars($address['country']) ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Trade References -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Trade References</div>
|
||||
<div class="card-body">
|
||||
<?php foreach ($trade_references as $ref): ?>
|
||||
<div class="mb-3 border-bottom pb-3">
|
||||
<p><strong>Company Name:</strong> <?= htmlspecialchars($ref['company_name']) ?></p>
|
||||
<p><strong>Contact Person:</strong> <?= htmlspecialchars($ref['contact_person']) ?></p>
|
||||
<p><strong>Email:</strong> <?= htmlspecialchars($ref['email']) ?></p>
|
||||
<p><strong>Phone:</strong> <?= htmlspecialchars($ref['phone']) ?></p>
|
||||
<p><strong>Address:</strong> <?= htmlspecialchars($ref['address']) ?></p>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bank Details -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Bank Details</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Bank Name:</strong> <?= htmlspecialchars($bank_details['bank_name']) ?></p>
|
||||
<p><strong>Branch:</strong> <?= htmlspecialchars($bank_details['branch']) ?></p>
|
||||
<p><strong>BSB Number:</strong> <?= htmlspecialchars($bank_details['bsb_number']) ?></p>
|
||||
<p><strong>Account Number:</strong> <?= htmlspecialchars($bank_details['account_number']) ?></p>
|
||||
<p><strong>Account Name:</strong> <?= htmlspecialchars($bank_details['account_name']) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Declaration and Signature -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Declaration and Signature</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Declaration:</strong> <?= nl2br(htmlspecialchars($application['declaration_text'])) ?></p>
|
||||
<?php if (!empty($application['signature_path'])): ?>
|
||||
<p><strong>Signature:</strong></p>
|
||||
<img src="<?= htmlspecialchars($application['signature_path']) ?>" alt="Signature" class="img-fluid">
|
||||
<?php else: ?>
|
||||
<p>No signature provided.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Application Summary -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Application Summary</div>
|
||||
<div class="card-body">
|
||||
<h5>Company Details</h5>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<p><strong>Customer Name:</strong> <?= htmlspecialchars($application['company_name']) ?></p>
|
||||
<p><strong>Major Product of Customer:</strong> <?= htmlspecialchars($application['major_product']) ?></p>
|
||||
<p><strong>Capital:</strong> <?= htmlspecialchars($application['capital']) ?> <?= htmlspecialchars($application['capital_currency']) ?></p>
|
||||
<p><strong>Main Shareholders:</strong> <?= htmlspecialchars($application['main_shareholders']) ?></p>
|
||||
<p><strong>Number of Employee:</strong> <?= htmlspecialchars($application['num_employees']) ?></p>
|
||||
<p><strong>Payment Terms AR:</strong> <?= htmlspecialchars($application['payment_terms_ar']) ?></p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6>Customer's P/L Information</h6>
|
||||
<p><strong>Year:</strong> <?= htmlspecialchars($application['pl_year']) ?></p>
|
||||
<p><strong>Net Sales:</strong> <?= htmlspecialchars($application['net_sales']) ?></p>
|
||||
<p><strong>Net Income Margin:</strong> <?= htmlspecialchars($application['net_income_margin']) ?></p>
|
||||
<p><strong>Net Income Margin Ratio(%):</strong> <?= htmlspecialchars($application['net_income_margin_ratio']) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6>ROHM Sales Target</h6>
|
||||
<p><strong>This Year:</strong> <?= htmlspecialchars($application['sales_target_this_year']) ?> KUS$</p>
|
||||
<p><strong>Next Year:</strong> <?= htmlspecialchars($application['sales_target_next_year']) ?> KUS$</p>
|
||||
<p><strong>After the Next:</strong> <?= htmlspecialchars($application['sales_target_after_next']) ?> KUS$</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6>Credit Information</h6>
|
||||
<p><strong>Rank:</strong> <?= htmlspecialchars($application['credit_rank']) ?></p>
|
||||
<p><strong>Limit (KUS$):</strong> <?= htmlspecialchars($application['credit_limit']) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6>Credit Research</h6>
|
||||
<p><strong>Status:</strong> <?= htmlspecialchars($application['credit_research_status']) ?></p>
|
||||
<p><strong>Reason:</strong> <?= htmlspecialchars($application['credit_research_reason']) ?></p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6>Other Details</h6>
|
||||
<p><strong>Tax Rate/Area (GST TYPE):</strong> <?= htmlspecialchars($application['tax_rate_area']) ?></p>
|
||||
<p><strong>Billing Type:</strong> <?= htmlspecialchars($application['billing_type']) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Principals Summary</div>
|
||||
<div class="card-body">
|
||||
<?php foreach ($principals as $principal): ?>
|
||||
<div class="mb-3 border-bottom pb-3">
|
||||
<p><strong>Name:</strong> <?= htmlspecialchars($principal['name']) ?></p>
|
||||
<p><strong>Title:</strong> <?= htmlspecialchars($principal['title']) ?></p>
|
||||
<p><strong>Ownership %:</strong> <?= htmlspecialchars($principal['ownership_percentage']) ?></p>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Contacts Summary</div>
|
||||
<div class="card-body">
|
||||
<?php foreach ($contacts as $contact): ?>
|
||||
<div class="mb-3 border-bottom pb-3">
|
||||
<p><strong>Name:</strong> <?= htmlspecialchars($contact['name']) ?> <?= $contact['is_primary'] ? '(Primary)' : '' ?></p>
|
||||
<p><strong>Email:</strong> <?= htmlspecialchars($contact['email']) ?></p>
|
||||
<p><strong>Phone:</strong> <?= htmlspecialchars($contact['phone']) ?></p>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Trade References Summary</div>
|
||||
<div class="card-body">
|
||||
<?php foreach ($trade_references as $ref): ?>
|
||||
<div class="mb-3 border-bottom pb-3">
|
||||
<p><strong>Company Name:</strong> <?= htmlspecialchars($ref['company_name']) ?></p>
|
||||
<p><strong>Contact Person:</strong> <?= htmlspecialchars($ref['contact_person']) ?></p>
|
||||
<p><strong>Email:</strong> <?= htmlspecialchars($ref['email']) ?></p>
|
||||
<p><strong>Phone:</strong> <?= htmlspecialchars($ref['phone']) ?></p>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Bank Reference Summary</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Bank Name:</strong> <?= htmlspecialchars($bank_details['bank_name']) ?></p>
|
||||
<p><strong>Branch:</strong> <?= htmlspecialchars($bank_details['branch']) ?></p>
|
||||
<p><strong>Account Number:</strong> <?= htmlspecialchars($bank_details['account_number']) ?></p>
|
||||
<p><strong>Account Name:</strong> <?= htmlspecialchars($bank_details['account_name']) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Approval Section -->
|
||||
<?php
|
||||
$approval_level = $application['approval_level'];
|
||||
$permission_needed = 'approve_level_' . $approval_level;
|
||||
if (hasPermission($permission_needed) && $application['status'] === 'PENDING_APPROVAL'):
|
||||
?>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">Approval Action</div>
|
||||
<div class="card-body">
|
||||
<form action="process_approval.php" method="POST">
|
||||
<input type="hidden" name="application_id" value="<?= $application['id'] ?>">
|
||||
<button type="submit" name="action" value="approve" class="btn btn-success">Approve</button>
|
||||
<button type="submit" name="action" value="reject" class="btn btn-danger">Reject</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
71
view_applications.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'includes/auth_helpers.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
redirect_if_not_authenticated();
|
||||
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query('SELECT id, application_id, company_name, status, created_at FROM customer_applications ORDER BY created_at DESC');
|
||||
$applications = $stmt->fetchAll();
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>View Applications</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Customer Master</a>
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Dashboard</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="logout.php">Logout</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container mt-4">
|
||||
<h2>Submitted Applications</h2>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Application ID</th>
|
||||
<th>Company Name</th>
|
||||
<th>Status</th>
|
||||
<th>Submitted At</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($applications)): ?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center">No applications found.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($applications as $app): ?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($app['application_id']) ?></td>
|
||||
<td><?= htmlspecialchars($app['company_name']) ?></td>
|
||||
<td><?= htmlspecialchars($app['status']) ?></td>
|
||||
<td><?= htmlspecialchars($app['created_at']) ?></td>
|
||||
<td>
|
||||
<a href="view_application.php?id=<?= $app['id'] ?>" class="btn btn-primary btn-sm">View</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||