V1.001 expanded requirements

This commit is contained in:
Flatlogic Bot 2025-12-04 02:32:25 +00:00
parent 45c5128c4f
commit be7c0d84bd
42 changed files with 3315 additions and 142 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

51
auth.php Normal file
View 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();
}

View 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;

View 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
);

View 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'

View 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)
);

View 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');

View 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);

View 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;

View 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;

View 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
View 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
View 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
View 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();
}
}

349
index.php
View File

@ -1,150 +1,217 @@
<?php <?php
declare(strict_types=1); session_start();
@ini_set('display_errors', '1'); require_once 'includes/auth_helpers.php';
@error_reporting(E_ALL);
@date_default_timezone_set('UTC'); // 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"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>New Style</title>
<?php <title>Dashboard - <?php echo htmlspecialchars($projectName); ?></title>
// Read project preview data from environment <meta name="description" content="<?php echo htmlspecialchars($projectDescription); ?>">
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; <!-- Open Graph / Facebook -->
?> <meta property="og:type" content="website">
<?php if ($projectDescription): ?> <meta property="og:title" content="<?php echo htmlspecialchars($projectName); ?>">
<!-- Meta description --> <meta property="og:description" content="<?php echo htmlspecialchars($projectDescription); ?>">
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' /> <?php if ($projectImageUrl): ?>
<!-- Open Graph meta tags --> <meta property="og:image" content="<?php echo htmlspecialchars($projectImageUrl); ?>">
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" /> <?php endif; ?>
<!-- Twitter meta tags -->
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" /> <!-- Twitter -->
<?php endif; ?> <meta property="twitter:card" content="summary_large_image">
<?php if ($projectImageUrl): ?> <meta property="twitter:title" content="<?php echo htmlspecialchars($projectName); ?>">
<!-- Open Graph image --> <meta property="twitter:description" content="<?php echo htmlspecialchars($projectDescription); ?>">
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" /> <?php if ($projectImageUrl): ?>
<!-- Twitter image --> <meta property="twitter:image" content="<?php echo htmlspecialchars($projectImageUrl); ?>">
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" /> <?php endif; ?>
<?php endif; ?>
<link rel="preconnect" href="https://fonts.googleapis.com"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet"> <style>
<style> body {
:root { background-color: #f8f9fa;
--bg-color-start: #6a11cb; }
--bg-color-end: #2575fc; </style>
--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>
</head> </head>
<body> <body>
<main> <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="card"> <div class="container-fluid">
<h1>Analyzing your requirements and generating your website…</h1> <a class="navbar-brand" href="#"><i class="bi bi-person-vcard"></i> <?php echo htmlspecialchars($projectName); ?></a>
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mainNav">
<span class="sr-only">Loading…</span> <span class="navbar-toggler-icon"></span>
</div> </button>
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p> <div class="collapse navbar-collapse" id="mainNav">
<p class="hint">This page will update automatically as the plan is implemented.</p> <ul class="navbar-nav me-auto mb-2 mb-lg-0">
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p> <li class="nav-item">
</div> <a class="nav-link active" href="#">Dashboard</a>
</main> </li>
<footer> <?php if (hasPermission('manage_users')): ?>
Page updated: <?= htmlspecialchars($now) ?> (UTC) <li class="nav-item">
</footer> <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> </body>
</html> </html>

65
login.php Normal file
View 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>&copy; <?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
View File

@ -0,0 +1,6 @@
<?php
session_start();
session_unset();
session_destroy();
header('Location: login.php');
exit();

185
manage_users.php Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1 @@
deny from all

408
view_application.php Normal file
View 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
View 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>