updating shipments fee
This commit is contained in:
parent
c1349af904
commit
c51c984fbc
@ -14,6 +14,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
|
||||
$companyPhone = trim($_POST['company_phone'] ?? '');
|
||||
$companyAddress = trim($_POST['company_address'] ?? '');
|
||||
$platformCharge = trim($_POST['platform_charge_percentage'] ?? '0');
|
||||
$pricingModel = trim($_POST['pricing_model'] ?? 'percentage');
|
||||
$timezone = trim($_POST['timezone'] ?? 'UTC');
|
||||
|
||||
$updates = [
|
||||
@ -22,6 +23,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
|
||||
'company_phone' => $companyPhone,
|
||||
'company_address' => $companyAddress,
|
||||
'platform_charge_percentage' => $platformCharge,
|
||||
'pricing_model' => $pricingModel,
|
||||
'timezone' => $timezone,
|
||||
'terms_en' => trim($_POST['terms_en'] ?? ''),
|
||||
'terms_ar' => trim($_POST['terms_ar'] ?? ''),
|
||||
@ -82,6 +84,7 @@ $currentEmail = $settings['company_email'] ?? '';
|
||||
$currentPhone = $settings['company_phone'] ?? '';
|
||||
$currentAddress = $settings['company_address'] ?? '';
|
||||
$currentPlatformCharge = $settings['platform_charge_percentage'] ?? '0';
|
||||
$currentPricingModel = $settings['pricing_model'] ?? 'percentage';
|
||||
$currentTimezone = $settings['timezone'] ?? 'UTC';
|
||||
$currentLogo = $settings['logo_path'] ?? '';
|
||||
$currentFavicon = $settings['favicon_path'] ?? '';
|
||||
@ -156,6 +159,26 @@ render_header('Company Profile', 'admin', true);
|
||||
<input type="text" name="company_address" class="form-control" value="<?= e($currentAddress) ?>">
|
||||
<div class="form-text">Displayed in the footer.</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<label class="form-label fw-bold">Pricing Model</label>
|
||||
<div class="card p-3 bg-light border-0">
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="radio" name="pricing_model" id="model_percentage" value="percentage" <?= $currentPricingModel === 'percentage' ? 'checked' : '' ?>>
|
||||
<label class="form-check-label" for="model_percentage">
|
||||
<strong>Percentage Fee Model</strong> (Default)<br>
|
||||
<span class="text-muted small">Shipper posts details. Truck Owners make offers. Platform adds fee on top of offer.</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="pricing_model" id="model_fixed" value="fixed_price" <?= $currentPricingModel === 'fixed_price' ? 'checked' : '' ?>>
|
||||
<label class="form-check-label" for="model_fixed">
|
||||
<strong>Shipper Offer & Confirmation</strong><br>
|
||||
<span class="text-muted small">Shipper sets price. Admin confirms. Truck Owner accepts fixed price.</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-bold">Platform Charge (%)</label>
|
||||
@ -163,7 +186,7 @@ render_header('Company Profile', 'admin', true);
|
||||
<input type="number" step="0.01" min="0" max="100" name="platform_charge_percentage" class="form-control" value="<?= e($currentPlatformCharge) ?>">
|
||||
<span class="input-group-text">%</span>
|
||||
</div>
|
||||
<div class="form-text">Percentage applied as a platform fee.</div>
|
||||
<div class="form-text">Percentage applied as a platform fee (only for Percentage Model).</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
|
||||
@ -145,7 +145,7 @@ if (!$isAjax):
|
||||
<div class="d-flex align-items-center gap-3 mb-4">
|
||||
<a href="admin_shipments.php" class="btn btn-light border text-secondary" title="<?= t('back') ?>">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"/>
|
||||
<path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<div>
|
||||
@ -289,6 +289,7 @@ if (!$isAjax):
|
||||
<div class="col-md-6">
|
||||
<label class="form-label"><?= t('status') ?></label>
|
||||
<select name="status" class="form-select">
|
||||
<option value="pending_approval" <?= $shipment['status'] === 'pending_approval' ? 'selected' : '' ?>><?= t('status_pending_approval') ?></option>
|
||||
<option value="posted" <?= $shipment['status'] === 'posted' ? 'selected' : '' ?>><?= t('status_posted') ?></option>
|
||||
<option value="offered" <?= $shipment['status'] === 'offered' ? 'selected' : '' ?>><?= t('status_offered') ?></option>
|
||||
<option value="confirmed" <?= $shipment['status'] === 'confirmed' ? 'selected' : '' ?>><?= t('status_confirmed') ?></option>
|
||||
|
||||
@ -6,7 +6,7 @@ require_once __DIR__ . '/includes/layout.php'; require_role('admin');
|
||||
$errors = [];
|
||||
$flash = null;
|
||||
|
||||
// Handle action (Delete)
|
||||
// Handle action (Delete / Approve)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'], $_POST['shipment_id'])) {
|
||||
$shipmentId = (int)$_POST['shipment_id'];
|
||||
$action = $_POST['action'];
|
||||
@ -14,6 +14,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'], $_POST['shi
|
||||
if ($action === 'delete') {
|
||||
db()->prepare("DELETE FROM shipments WHERE id = ?")->execute([$shipmentId]);
|
||||
$flash = t('flash_shipment_deleted');
|
||||
} elseif ($action === 'approve') {
|
||||
db()->prepare("UPDATE shipments SET status = 'posted' WHERE id = ?")->execute([$shipmentId]);
|
||||
$flash = t('success_status');
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +37,7 @@ if ($q !== '') {
|
||||
$params = array_merge($params, array_fill(0, 5, $likeQ));
|
||||
}
|
||||
|
||||
if ($status !== '' && in_array($status, ['posted', 'offered', 'confirmed', 'in_transit', 'delivered'])) {
|
||||
if ($status !== '' && in_array($status, ['posted', 'offered', 'confirmed', 'in_transit', 'delivered', 'pending_approval'])) {
|
||||
$whereClause .= " AND status = ?";
|
||||
$params[] = $status;
|
||||
}
|
||||
@ -95,6 +98,7 @@ render_header(t('manage_shipments'), 'admin', true);
|
||||
<label class="form-label small text-muted"><?= t('status') ?></label>
|
||||
<select name="status" class="form-select">
|
||||
<option value=""><?= t('all_statuses') ?></option>
|
||||
<option value="pending_approval" <?= $status === 'pending_approval' ? 'selected' : '' ?>><?= t('status_pending_approval') ?></option>
|
||||
<option value="posted" <?= $status === 'posted' ? 'selected' : '' ?>><?= t('status_posted') ?></option>
|
||||
<option value="offered" <?= $status === 'offered' ? 'selected' : '' ?>><?= t('status_offered') ?></option>
|
||||
<option value="confirmed" <?= $status === 'confirmed' ? 'selected' : '' ?>><?= t('status_confirmed') ?></option>
|
||||
@ -149,6 +153,9 @@ render_header(t('manage_shipments'), 'admin', true);
|
||||
<?php if (!empty($shipment['shipment_type'])): ?>
|
||||
<div class="mt-1"><span class="badge bg-light text-secondary border"><?= e(t('type_' . strtolower($shipment['shipment_type']))) ?></span></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($shipment['target_price'])): ?>
|
||||
<div class="text-info small fw-bold mt-1"><?= t('target_price') ?>: $<?= e($shipment['target_price']) ?></div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small"><span class="text-muted"><?= t('pick_label') ?></span> <?= e($shipment['pickup_date']) ?></div>
|
||||
@ -162,11 +169,20 @@ render_header(t('manage_shipments'), 'admin', true);
|
||||
elseif ($shipment['status'] === 'confirmed') $statusClass = 'bg-success-subtle text-success';
|
||||
elseif ($shipment['status'] === 'in_transit') $statusClass = 'bg-warning-subtle text-warning';
|
||||
elseif ($shipment['status'] === 'delivered') $statusClass = 'bg-dark-subtle text-dark';
|
||||
elseif ($shipment['status'] === 'pending_approval') $statusClass = 'bg-warning text-dark';
|
||||
?>
|
||||
<span class="badge <?= $statusClass ?>"><?= e(status_label($shipment['status'])) ?></span>
|
||||
</td>
|
||||
<td class="text-end pe-4">
|
||||
<div class="d-inline-flex gap-1 align-items-center">
|
||||
<?php if ($shipment['status'] === 'pending_approval'): ?>
|
||||
<form method="post" class="d-inline m-0 p-0"> <?= csrf_field() ?>
|
||||
<input type="hidden" name="shipment_id" value="<?= e((string)$shipment['id']) ?>">
|
||||
<button type="submit" name="action" value="approve" class="btn btn-sm p-1 border-0 bg-transparent text-success" title="<?= t('approve') ?>">
|
||||
<i class="bi bi-check-circle-fill"></i>
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<a href="shipment_detail.php?id=<?= e((string)$shipment['id']) ?>" class="btn btn-sm p-1 border-0 bg-transparent text-primary" title="<?= t('view_shipment') ?>">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
|
||||
11
check_status_enum.php
Normal file
11
check_status_enum.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
try {
|
||||
$stmt = db()->query("SHOW COLUMNS FROM shipments LIKE 'status'");
|
||||
$row = $stmt->fetch();
|
||||
echo "Type: " . $row['Type'] . "\n";
|
||||
} catch (Throwable $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
13
db/migrations/add_pending_approval_status.php
Normal file
13
db/migrations/add_pending_approval_status.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config.php';
|
||||
|
||||
try {
|
||||
echo "Adding 'pending_approval' to shipments status enum...\n";
|
||||
// MariaDB/MySQL ALTER TABLE to modify column
|
||||
$sql = "ALTER TABLE shipments MODIFY COLUMN status ENUM('pending_approval', 'posted','offered','confirmed','in_transit','delivered') NOT NULL DEFAULT 'posted'";
|
||||
db()->exec($sql);
|
||||
echo "Migration successful.\n";
|
||||
} catch (PDOException $e) {
|
||||
echo "Migration failed: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
37
db/migrations/add_pricing_model.php
Normal file
37
db/migrations/add_pricing_model.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config.php';
|
||||
$pdo = db();
|
||||
|
||||
try {
|
||||
// Add target_price column to shipments if it doesn't exist
|
||||
$pdo->exec("
|
||||
SET @dbname = DATABASE();
|
||||
SET @tablename = 'shipments';
|
||||
SET @columnname = 'target_price';
|
||||
SET @preparedStatement = (SELECT IF(
|
||||
(
|
||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE
|
||||
(table_name = @tablename)
|
||||
AND (table_schema = @dbname)
|
||||
AND (column_name = @columnname)
|
||||
) > 0,
|
||||
'SELECT 1',
|
||||
'ALTER TABLE shipments ADD COLUMN target_price DECIMAL(10,2) DEFAULT NULL AFTER weight_tons'
|
||||
));
|
||||
PREPARE alterIfNotExists FROM @preparedStatement;
|
||||
EXECUTE alterIfNotExists;
|
||||
DEALLOCATE PREPARE alterIfNotExists;
|
||||
");
|
||||
echo "Added target_price column to shipments.\n";
|
||||
|
||||
// Insert default pricing_model setting
|
||||
$pdo->exec("
|
||||
INSERT IGNORE INTO settings (setting_key, setting_value) VALUES ('pricing_model', 'percentage');
|
||||
");
|
||||
echo "Added pricing_model setting.\n";
|
||||
|
||||
} catch (PDOException $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
@ -282,7 +282,7 @@ $translations = [
|
||||
'address' => 'Address',
|
||||
'shipper_details' => 'Shipper Details',
|
||||
'company_name' => 'Company Name',
|
||||
'truck_details' => 'Truck Details',
|
||||
'truck_details' => 'تفاصيل الشاحنة',
|
||||
'truck_type' => 'Truck Type',
|
||||
'load_capacity' => 'Load Capacity (Tons)',
|
||||
'plate_no' => 'Plate Number',
|
||||
@ -333,6 +333,9 @@ $translations = [
|
||||
'type_frozen' => 'Frozen',
|
||||
'type_cold' => 'Cold',
|
||||
'type_dry' => 'Dry',
|
||||
'target_price' => 'Target Price',
|
||||
'status_pending_approval' => 'Pending Approval',
|
||||
'pending_approval_msg' => 'Your shipment is pending admin approval.',
|
||||
),
|
||||
"ar" => array (
|
||||
'app_name' => 'CargoLink',
|
||||
@ -654,6 +657,9 @@ $translations = [
|
||||
'type_frozen' => 'مجمد',
|
||||
'type_cold' => 'مبرد',
|
||||
'type_dry' => 'جاف',
|
||||
'target_price' => 'السعر المستهدف',
|
||||
'status_pending_approval' => 'بانتظار الموافقة',
|
||||
'pending_approval_msg' => 'شحنتك بانتظار موافقة الإدارة.',
|
||||
)
|
||||
];
|
||||
|
||||
@ -806,6 +812,7 @@ function status_label(string $status): string
|
||||
'confirmed' => t('status_confirmed'),
|
||||
'in_transit' => t('status_in_transit'),
|
||||
'delivered' => t('status_delivered'),
|
||||
'pending_approval' => t('status_pending_approval'),
|
||||
];
|
||||
return $map[$status] ?? $status;
|
||||
}
|
||||
@ -916,4 +923,4 @@ try {
|
||||
if ($tz && in_array($tz, DateTimeZone::listIdentifiers())) {
|
||||
date_default_timezone_set($tz);
|
||||
}
|
||||
} catch (Throwable $e) {}
|
||||
} catch (Throwable $e) {}
|
||||
@ -27,6 +27,7 @@ $isAssignedTruckOwner = $shipment && $shipment['truck_owner_id'] == $currentUser
|
||||
// Platform Fee Configuration
|
||||
$settings = get_settings();
|
||||
$platformFeePercentage = (float)($settings['platform_charge_percentage'] ?? 0) / 100;
|
||||
$pricingModel = $settings['pricing_model'] ?? 'percentage';
|
||||
|
||||
// Handle POST actions
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
|
||||
@ -35,6 +36,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token();
|
||||
if ($action === 'submit_offer') { if (!$isTruckOwner && !$isAdmin) { $errors[] = 'Only truck owners can submit offers.'; }
|
||||
$offerOwner = trim($_POST['offer_owner'] ?? '');
|
||||
$offerPrice = trim($_POST['offer_price'] ?? '');
|
||||
|
||||
// Enforce fixed price logic if applicable
|
||||
if ($pricingModel === 'fixed_price' && !empty($shipment['target_price'])) {
|
||||
$offerPrice = $shipment['target_price'];
|
||||
}
|
||||
|
||||
if ($offerOwner === '' || $offerPrice === '') {
|
||||
$errors[] = t('error_required');
|
||||
} elseif (!is_numeric($offerPrice)) {
|
||||
@ -196,7 +203,10 @@ render_header(t('shipment_detail'));
|
||||
<h2 class="section-title mb-1"><?= e(t('shipment_detail')) ?> #<?= e($shipment['id']) ?></h2>
|
||||
<p class="muted mb-0"><?= e(t('created_at')) ?>: <?= e($shipment['created_at']) ?></p>
|
||||
</div>
|
||||
<span class="badge-status <?= e($shipment['status']) ?>"><?= e(status_label($shipment['status'])) ?></span>
|
||||
<?php
|
||||
$statusBadgeClass = ($shipment['status'] === 'pending_approval') ? 'bg-warning text-dark' : $shipment['status'];
|
||||
?>
|
||||
<span class="badge-status <?= e($statusBadgeClass) ?>"><?= e(status_label($shipment['status'])) ?></span>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
@ -243,6 +253,14 @@ render_header(t('shipment_detail'));
|
||||
<div class="small text-muted"><?= e(t('best_offer')) ?></div>
|
||||
<div class="fw-semibold"><?= $shipment['offer_price'] ? e($shipment['offer_price'] . ' / ' . ($shipment['offer_owner'] ?? '')) : e(t('no_offers')) ?></div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($shipment['target_price'])): ?>
|
||||
<div class="col-md-6">
|
||||
<div class="small text-muted"><?= e(t('target_price')) ?></div>
|
||||
<div class="fw-semibold text-info">$<?= e($shipment['target_price']) ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($shipment['payment_status'] === 'paid'): ?>
|
||||
<div class="col-12">
|
||||
<div class="alert alert-success d-flex align-items-center mb-0">
|
||||
@ -329,6 +347,11 @@ render_header(t('shipment_detail'));
|
||||
<i class="bi bi-hourglass-split fs-1 text-muted mb-3 d-block"></i>
|
||||
<p class="mb-0 text-muted">Waiting for truck owners to submit offers.</p>
|
||||
</div>
|
||||
<?php elseif ($shipment['status'] === 'pending_approval'): ?>
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-clipboard-check fs-1 text-warning mb-3 d-block"></i>
|
||||
<p class="mb-0 text-muted"><?= t('pending_approval_msg') ?></p>
|
||||
</div>
|
||||
<?php elseif ($shipment['status'] === 'confirmed' || $shipment['status'] === 'in_transit' || $shipment['status'] === 'delivered'): ?>
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-check-circle-fill fs-1 text-success mb-3 d-block"></i>
|
||||
@ -373,15 +396,31 @@ render_header(t('shipment_detail'));
|
||||
<label class="form-label"><?= e(t('offer_owner')) ?></label>
|
||||
<input class="form-control" name="offer_owner" value="<?= e($shipment['offer_owner'] ?? '') ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= e(t('offer_price')) ?></label>
|
||||
<input class="form-control" name="offer_price" type="number" step="0.01" min="0.1" value="<?= e($shipment['offer_price'] ?? '') ?>" required>
|
||||
</div>
|
||||
<button class="btn btn-primary w-100" type="submit"><?= e(t('submit_offer')) ?></button>
|
||||
|
||||
<?php if ($pricingModel === 'fixed_price' && !empty($shipment['target_price'])): ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= e(t('target_price')) ?></label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input class="form-control bg-light" value="<?= e($shipment['target_price']) ?>" readonly>
|
||||
<input type="hidden" name="offer_price" value="<?= e($shipment['target_price']) ?>">
|
||||
</div>
|
||||
<div class="form-text text-success fw-bold"><i class="bi bi-check-circle me-1"></i> Fixed Price Offer</div>
|
||||
</div>
|
||||
<button class="btn btn-success w-100 fw-bold shadow-sm" type="submit">
|
||||
Accept Load ($<?= e($shipment['target_price']) ?>)
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= e(t('offer_price')) ?></label>
|
||||
<input class="form-control" name="offer_price" type="number" step="0.01" min="0.1" value="<?= e($shipment['offer_price'] ?? '') ?>" required>
|
||||
</div>
|
||||
<button class="btn btn-primary w-100" type="submit"><?= e(t('submit_offer')) ?></button>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-info">
|
||||
This shipment is already confirmed/processed.
|
||||
This shipment is already confirmed/processed or pending approval.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@ require_once __DIR__ . '/includes/NotificationService.php';
|
||||
ensure_schema();
|
||||
|
||||
$errors = [];
|
||||
$settings = get_settings();
|
||||
$pricingModel = $settings['pricing_model'] ?? 'percentage';
|
||||
|
||||
// Try to pre-fill from profile if logged in
|
||||
$prefillName = $_SESSION['shipper_name'] ?? '';
|
||||
@ -34,19 +36,26 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'creat
|
||||
$pickupDate = trim($_POST['pickup_date'] ?? '');
|
||||
$deliveryDate = trim($_POST['delivery_date'] ?? '');
|
||||
$payment = $_POST['payment_method'] ?? 'thawani';
|
||||
|
||||
$targetPrice = ($pricingModel === 'fixed_price') ? trim($_POST['target_price'] ?? '') : null;
|
||||
$initialStatus = ($pricingModel === 'fixed_price') ? 'pending_approval' : 'posted';
|
||||
|
||||
if ($shipperName === '' || $shipperCompany === '' || $origin === '' || $destination === '' || $cargo === '' || $weight === '' || $pickupDate === '' || $deliveryDate === '') {
|
||||
$errors[] = t('error_required');
|
||||
} elseif (!is_numeric($weight)) {
|
||||
$errors[] = t('error_invalid');
|
||||
}
|
||||
|
||||
if ($pricingModel === 'fixed_price' && (!is_numeric($targetPrice) || $targetPrice <= 0)) {
|
||||
$errors[] = t('error_invalid');
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$shipperId = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null;
|
||||
|
||||
$stmt = db()->prepare(
|
||||
"INSERT INTO shipments (shipper_id, shipper_name, shipper_company, origin_city, destination_city, shipment_type, cargo_description, weight_tons, pickup_date, delivery_date, payment_method)
|
||||
VALUES (:shipper_id, :shipper_name, :shipper_company, :origin_city, :destination_city, :shipment_type, :cargo_description, :weight_tons, :pickup_date, :delivery_date, :payment_method)"
|
||||
"INSERT INTO shipments (shipper_id, shipper_name, shipper_company, origin_city, destination_city, shipment_type, cargo_description, weight_tons, pickup_date, delivery_date, payment_method, status, target_price)
|
||||
VALUES (:shipper_id, :shipper_name, :shipper_company, :origin_city, :destination_city, :shipment_type, :cargo_description, :weight_tons, :pickup_date, :delivery_date, :payment_method, :status, :target_price)"
|
||||
);
|
||||
$stmt->execute([
|
||||
':shipper_id' => $shipperId,
|
||||
@ -60,6 +69,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'creat
|
||||
':pickup_date' => $pickupDate,
|
||||
':delivery_date' => $deliveryDate,
|
||||
':payment_method' => $payment,
|
||||
':status' => $initialStatus,
|
||||
':target_price' => $targetPrice,
|
||||
]);
|
||||
|
||||
$newShipmentId = db()->lastInsertId();
|
||||
@ -78,7 +89,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'creat
|
||||
}
|
||||
}
|
||||
|
||||
set_flash('success', t('success_shipment'));
|
||||
$msg = ($initialStatus === 'pending_approval') ? t('pending_approval_msg') : t('success_shipment');
|
||||
set_flash('success', $msg);
|
||||
header('Location: ' . url_with_lang('shipper_dashboard.php'));
|
||||
exit;
|
||||
}
|
||||
@ -107,9 +119,17 @@ $stats = [
|
||||
|
||||
try {
|
||||
if ($filterCompany) {
|
||||
$stats['total'] = (int)db()->prepare("SELECT COUNT(*) FROM shipments WHERE shipper_company = ?")->execute([$filterCompany]) ? (int)db()->query("SELECT COUNT(*) FROM shipments WHERE shipper_company = " . db()->quote($filterCompany))->fetchColumn() : 0;
|
||||
$stats['active'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE shipper_company = " . db()->quote($filterCompany) . " AND status != 'delivered'")->fetchColumn();
|
||||
$stats['delivered'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE shipper_company = " . db()->quote($filterCompany) . " AND status = 'delivered'")->fetchColumn();
|
||||
$stmt = db()->prepare("SELECT COUNT(*) FROM shipments WHERE shipper_company = ?");
|
||||
$stmt->execute([$filterCompany]);
|
||||
$stats['total'] = (int)$stmt->fetchColumn();
|
||||
|
||||
$stmt = db()->prepare("SELECT COUNT(*) FROM shipments WHERE shipper_company = ? AND status != 'delivered'");
|
||||
$stmt->execute([$filterCompany]);
|
||||
$stats['active'] = (int)$stmt->fetchColumn();
|
||||
|
||||
$stmt = db()->prepare("SELECT COUNT(*) FROM shipments WHERE shipper_company = ? AND status = 'delivered'");
|
||||
$stmt->execute([$filterCompany]);
|
||||
$stats['delivered'] = (int)$stmt->fetchColumn();
|
||||
} else {
|
||||
$stats['total'] = (int)db()->query("SELECT COUNT(*) FROM shipments")->fetchColumn();
|
||||
$stats['active'] = (int)db()->query("SELECT COUNT(*) FROM shipments WHERE status != 'delivered'")->fetchColumn();
|
||||
@ -230,6 +250,17 @@ $flash = get_flash();
|
||||
<label class="form-label text-muted small fw-bold"><?= e(t('cargo')) ?></label>
|
||||
<input class="form-control" name="cargo_description" placeholder="<?= e(t('cargo_placeholder') ?? 'e.g. 20 Pallets of Electronics') ?>" required>
|
||||
</div>
|
||||
|
||||
<?php if ($pricingModel === 'fixed_price'): ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small fw-bold"><?= e(t('target_price')) ?></label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input class="form-control" name="target_price" type="number" step="0.01" min="0.1" required>
|
||||
</div>
|
||||
<div class="form-text small text-info"><i class="bi bi-info-circle me-1"></i><?= e(t('pending_approval_msg')) ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="row g-3 mb-3">
|
||||
<div class="col-md-6">
|
||||
@ -296,8 +327,13 @@ $flash = get_flash();
|
||||
<span class="badge bg-light text-secondary border"><?= e(t('type_' . strtolower($row['shipment_type']))) ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($row['target_price'])): ?>
|
||||
<div class="text-xs text-info mt-1 fw-bold">
|
||||
<?= e(t('target_price')) ?>: $<?= e($row['target_price']) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><span class="badge <?= e($row['status']) ?> rounded-pill px-3 py-2"><?= e(status_label($row['status'])) ?></span></td>
|
||||
<td><span class="badge <?= e($row['status'] === 'pending_approval' ? 'bg-warning text-dark' : $row['status']) ?> rounded-pill px-3 py-2"><?= e(status_label($row['status'])) ?></span></td>
|
||||
<td>
|
||||
<?php if ($row['offer_price']): ?>
|
||||
<div class="fw-bold text-success">$<?= e($row['offer_price']) ?></div>
|
||||
|
||||
@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
require_once __DIR__ . '/includes/layout.php'; require_role('truck_owner');
|
||||
|
||||
$userId = $_SESSION['user_id'];
|
||||
$settings = get_settings();
|
||||
$pricingModel = $settings['pricing_model'] ?? 'percentage';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'add_truck') {
|
||||
$truckType = trim($_POST['truck_type'] ?? '');
|
||||
@ -29,81 +31,147 @@ $trucks = db()->prepare("SELECT * FROM trucks WHERE user_id = ?");
|
||||
$trucks->execute([$userId]);
|
||||
$myTrucks = $trucks->fetchAll();
|
||||
|
||||
// Fetch Available Shipments
|
||||
$availShipments = [];
|
||||
try {
|
||||
$stmt = db()->query("SELECT * FROM shipments WHERE status = 'posted' ORDER BY created_at DESC");
|
||||
$availShipments = $stmt->fetchAll();
|
||||
} catch (Throwable $e) {}
|
||||
|
||||
render_header('Truck Owner Dashboard', 'owner');
|
||||
$flash = get_flash();
|
||||
?>
|
||||
|
||||
<div class="page-intro mb-4">
|
||||
<h1 class="section-title mb-1">Truck Owner Dashboard</h1>
|
||||
<p class="muted mb-0">Manage your trucks and view their approval status.</p>
|
||||
<p class="muted mb-0">Manage your trucks and view available shipments.</p>
|
||||
</div>
|
||||
|
||||
<?php if ($flash): ?>
|
||||
<div class="alert alert-<?= $flash['type'] ?>" data-auto-dismiss="true"><?= e($flash['message']) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="panel p-4 mb-4">
|
||||
<h5 class="mb-3">Add New Truck</h5>
|
||||
<form method="post" class="row g-3"> <?= csrf_field() ?>
|
||||
<input type="hidden" name="action" value="add_truck">
|
||||
<div class="col-md-2">
|
||||
<input type="text" name="truck_type" class="form-control" placeholder="Truck Type" required>
|
||||
<div class="row g-4">
|
||||
<div class="col-lg-4">
|
||||
<div class="panel p-4 mb-4">
|
||||
<h5 class="mb-3">Add New Truck</h5>
|
||||
<form method="post" class="row g-3"> <?= csrf_field() ?>
|
||||
<input type="hidden" name="action" value="add_truck">
|
||||
<div class="col-12">
|
||||
<label class="form-label small text-muted">Truck Type</label>
|
||||
<input type="text" name="truck_type" class="form-control" placeholder="e.g. Refrigerated" required>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-muted">Capacity (T)</label>
|
||||
<input type="number" name="load_capacity" class="form-control" step="0.01" required>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-muted">Plate No</label>
|
||||
<input type="text" name="plate_no" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-muted">Reg. Expiry</label>
|
||||
<input type="date" name="registration_expiry_date" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-muted">Ins. Expiry</label>
|
||||
<input type="date" name="insurance_expiry_date" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-12 pt-2">
|
||||
<button type="submit" class="btn btn-primary w-100">Add Truck</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input type="number" name="load_capacity" class="form-control" placeholder="Capacity (T)" step="0.01" required>
|
||||
|
||||
<div class="panel p-4">
|
||||
<h5 class="mb-3">My Trucks</h5>
|
||||
<?php if (!$myTrucks): ?>
|
||||
<p class="text-muted small">No trucks registered yet.</p>
|
||||
<?php else: ?>
|
||||
<div class="list-group list-group-flush">
|
||||
<?php foreach ($myTrucks as $truck): ?>
|
||||
<?php
|
||||
$isExpired = (strtotime($truck['registration_expiry_date']) < time()) || (strtotime($truck['insurance_expiry_date']) < time());
|
||||
?>
|
||||
<div class="list-group-item px-0 py-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<strong class="text-dark"><?= e($truck['plate_no']) ?></strong>
|
||||
<?php if ($isExpired): ?>
|
||||
<span class="badge bg-danger">Expired</span>
|
||||
<?php elseif ($truck['is_approved']): ?>
|
||||
<span class="badge bg-success">Approved</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-warning text-dark">Pending</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="small text-muted"><?= e($truck['truck_type']) ?> • <?= e($truck['load_capacity']) ?> Tons</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input type="text" name="plate_no" class="form-control" placeholder="Plate No" required>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-8">
|
||||
<div class="panel p-4 h-100">
|
||||
<h5 class="mb-3">Available Shipments</h5>
|
||||
<?php if (!$availShipments): ?>
|
||||
<div class="text-center p-5 text-muted">
|
||||
<i class="bi bi-inbox fs-1 mb-3 d-block opacity-50"></i>
|
||||
<p class="mb-0">No shipments available at the moment.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table align-middle mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-uppercase small text-muted border-top-0">Route</th>
|
||||
<th class="text-uppercase small text-muted border-top-0">Details</th>
|
||||
<th class="text-uppercase small text-muted border-top-0">Dates</th>
|
||||
<th class="text-uppercase small text-muted border-top-0 text-end">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($availShipments as $row): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="fw-medium"><?= e($row['origin_city']) ?></span>
|
||||
<i class="bi bi-arrow-right text-muted small"></i>
|
||||
<span class="fw-medium"><?= e($row['destination_city']) ?></span>
|
||||
</div>
|
||||
<?php if (!empty($row['shipment_type'])): ?>
|
||||
<div class="text-xs text-muted mt-1">
|
||||
<span class="badge bg-light text-secondary border"><?= e(t('type_' . strtolower($row['shipment_type']))) ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($row['target_price'])): ?>
|
||||
<div class="text-success small fw-bold mt-1">
|
||||
Price: $<?= e($row['target_price']) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small text-dark fw-bold"><?= e($row['cargo_description']) ?></div>
|
||||
<div class="small text-muted"><?= e($row['weight_tons']) ?> Tons • <?= e($row['payment_method']) ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small"><span class="text-muted">Pick:</span> <?= e(date('M d', strtotime($row['pickup_date']))) ?></div>
|
||||
<div class="small"><span class="text-muted">Drop:</span> <?= e(date('M d', strtotime($row['delivery_date']))) ?></div>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<a href="<?= e(url_with_lang('shipment_detail.php', ['id' => $row['id']])) ?>" class="btn btn-sm btn-outline-primary rounded-pill px-3">
|
||||
View
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input type="date" name="registration_expiry_date" class="form-control" required title="Registration Expiry Date">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input type="date" name="insurance_expiry_date" class="form-control" required title="Insurance Expiry Date">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-primary w-100">Add Truck</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="panel p-4">
|
||||
<h5 class="mb-3">My Trucks</h5>
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Truck Type</th>
|
||||
<th>Capacity (T)</th>
|
||||
<th>Plate No</th>
|
||||
<th>Reg Expiry</th>
|
||||
<th>Ins Expiry</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($myTrucks as $truck): ?>
|
||||
<?php
|
||||
$isExpired = (strtotime($truck['registration_expiry_date']) < time()) || (strtotime($truck['insurance_expiry_date']) < time());
|
||||
?>
|
||||
<tr class="<?= $isExpired ? 'table-danger' : '' ?>">
|
||||
<td><?= e($truck['truck_type']) ?></td>
|
||||
<td><?= e($truck['load_capacity']) ?></td>
|
||||
<td><?= e($truck['plate_no']) ?></td>
|
||||
<td><?= e($truck['registration_expiry_date']) ?></td>
|
||||
<td><?= e($truck['insurance_expiry_date']) ?></td>
|
||||
<td>
|
||||
<?php if ($isExpired): ?>
|
||||
<span class="badge bg-danger">Expired</span>
|
||||
<?php elseif ($truck['is_approved']): ?>
|
||||
<span class="badge bg-success">Approved</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-warning text-dark">Pending</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php render_footer(); ?>
|
||||
Loading…
x
Reference in New Issue
Block a user