migrate to gtea from bistbucket
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_delivery_zones', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
$table->string('name');
|
||||
$table->string('slug')->unique();
|
||||
$table->text('description')->nullable();
|
||||
$table->string('color', 7)->default('#3B82F6');
|
||||
$table->json('coordinates'); // Polygon coordinates
|
||||
$table->decimal('min_lat', 10, 7)->nullable();
|
||||
$table->decimal('max_lat', 10, 7)->nullable();
|
||||
$table->decimal('min_lng', 10, 7)->nullable();
|
||||
$table->decimal('max_lng', 10, 7)->nullable();
|
||||
$table->integer('priority')->default(0);
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->boolean('is_default')->default(false);
|
||||
$table->decimal('max_delivery_distance', 8, 2)->nullable();
|
||||
$table->json('operating_hours')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['is_active', 'priority']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_delivery_zones');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_zone_pricing_rules', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
$table->foreignId('zone_id')->constrained('restaurant_delivery_zones')->cascadeOnDelete();
|
||||
$table->string('name');
|
||||
$table->integer('priority')->default(1);
|
||||
$table->boolean('is_active')->default(true);
|
||||
|
||||
// Base pricing
|
||||
$table->decimal('base_fare', 10, 2)->default(30.00);
|
||||
$table->decimal('minimum_fare', 10, 2)->default(30.00);
|
||||
$table->decimal('per_km_charge', 10, 2)->default(8.00);
|
||||
$table->decimal('free_distance', 8, 2)->default(0);
|
||||
$table->decimal('max_distance', 8, 2)->nullable();
|
||||
|
||||
// Surge pricing
|
||||
$table->boolean('surge_enabled')->default(false);
|
||||
$table->decimal('surge_multiplier', 4, 2)->default(1.00);
|
||||
|
||||
// Conditions
|
||||
$table->json('conditions')->nullable();
|
||||
$table->time('valid_from')->nullable();
|
||||
$table->time('valid_until')->nullable();
|
||||
$table->integer('valid_days')->nullable(); // Bitmask for days
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['zone_id', 'is_active', 'priority']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_zone_pricing_rules');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_riders', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
$table->foreignId('user_id')->nullable()->constrained()->nullOnDelete();
|
||||
|
||||
// Personal information
|
||||
$table->string('first_name');
|
||||
$table->string('last_name');
|
||||
$table->string('phone')->unique();
|
||||
$table->string('email')->nullable();
|
||||
$table->string('photo')->nullable();
|
||||
$table->date('date_of_birth')->nullable();
|
||||
$table->string('national_id')->nullable();
|
||||
$table->string('emergency_contact')->nullable();
|
||||
|
||||
// Rider type and status
|
||||
$table->enum('type', ['internal', 'freelance', 'third_party'])->default('freelance');
|
||||
$table->enum('status', ['pending', 'active', 'suspended', 'inactive'])->default('pending');
|
||||
|
||||
// Vehicle information
|
||||
$table->enum('vehicle_type', ['bicycle', 'motorcycle', 'car', 'van'])->default('motorcycle');
|
||||
$table->string('vehicle_number')->nullable();
|
||||
$table->string('vehicle_model')->nullable();
|
||||
$table->string('vehicle_color')->nullable();
|
||||
$table->string('license_number')->nullable();
|
||||
$table->date('license_expiry')->nullable();
|
||||
|
||||
// Verification
|
||||
$table->boolean('is_verified')->default(false);
|
||||
$table->timestamp('verified_at')->nullable();
|
||||
$table->string('verified_by')->nullable();
|
||||
$table->json('verification_documents')->nullable();
|
||||
|
||||
// Commission settings
|
||||
$table->enum('commission_type', ['fixed', 'percentage', 'per_km', 'hybrid'])->default('percentage');
|
||||
$table->decimal('commission_rate', 8, 2)->default(70);
|
||||
$table->decimal('base_commission', 8, 2)->nullable(); // For hybrid
|
||||
$table->decimal('per_km_rate', 8, 2)->nullable(); // For hybrid
|
||||
|
||||
// Current location
|
||||
$table->decimal('current_latitude', 10, 7)->nullable();
|
||||
$table->decimal('current_longitude', 10, 7)->nullable();
|
||||
$table->timestamp('last_location_update')->nullable();
|
||||
|
||||
// Stats
|
||||
$table->decimal('rating', 3, 2)->default(5.00);
|
||||
$table->unsignedInteger('rating_count')->default(0);
|
||||
$table->unsignedInteger('total_deliveries')->default(0);
|
||||
$table->unsignedInteger('successful_deliveries')->default(0);
|
||||
$table->unsignedInteger('cancelled_deliveries')->default(0);
|
||||
$table->unsignedInteger('failed_deliveries')->default(0);
|
||||
$table->decimal('acceptance_rate', 5, 2)->default(100.00);
|
||||
$table->decimal('completion_rate', 5, 2)->default(100.00);
|
||||
|
||||
// Online status
|
||||
$table->boolean('is_online')->default(false);
|
||||
$table->timestamp('last_online_at')->nullable();
|
||||
$table->timestamp('went_offline_at')->nullable();
|
||||
|
||||
// Firebase
|
||||
$table->string('fcm_token')->nullable();
|
||||
$table->string('device_id')->nullable();
|
||||
|
||||
// Banking/Payment
|
||||
$table->string('bank_name')->nullable();
|
||||
$table->string('bank_account_number')->nullable();
|
||||
$table->string('bank_account_name')->nullable();
|
||||
$table->string('mobile_wallet_number')->nullable();
|
||||
$table->string('mobile_wallet_provider')->nullable();
|
||||
|
||||
// Zones
|
||||
$table->json('assigned_zones')->nullable();
|
||||
|
||||
// Metadata
|
||||
$table->json('meta')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['is_online', 'status']);
|
||||
$table->index(['current_latitude', 'current_longitude']);
|
||||
$table->index('rating');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_riders');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_deliveries', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
$table->string('tracking_code', 20)->unique();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
$table->foreignId('rider_id')->nullable()->constrained('restaurant_riders')->nullOnDelete();
|
||||
$table->foreignId('zone_id')->nullable()->constrained('restaurant_delivery_zones')->nullOnDelete();
|
||||
|
||||
// Polymorphic relation to order
|
||||
$table->morphs('orderable');
|
||||
|
||||
// Status
|
||||
$table->string('status')->default('pending');
|
||||
$table->string('previous_status')->nullable();
|
||||
$table->timestamp('status_changed_at')->nullable();
|
||||
|
||||
// Restaurant/Pickup details
|
||||
$table->string('restaurant_name')->nullable();
|
||||
$table->string('pickup_address');
|
||||
$table->decimal('pickup_latitude', 10, 7);
|
||||
$table->decimal('pickup_longitude', 10, 7);
|
||||
$table->string('pickup_contact_name')->nullable();
|
||||
$table->string('pickup_contact_phone')->nullable();
|
||||
$table->text('pickup_instructions')->nullable();
|
||||
|
||||
// Customer/Drop details
|
||||
$table->string('customer_name')->nullable();
|
||||
$table->string('drop_address');
|
||||
$table->decimal('drop_latitude', 10, 7);
|
||||
$table->decimal('drop_longitude', 10, 7);
|
||||
$table->string('drop_contact_name')->nullable();
|
||||
$table->string('drop_contact_phone')->nullable();
|
||||
$table->text('drop_instructions')->nullable();
|
||||
$table->string('drop_floor')->nullable();
|
||||
$table->string('drop_apartment')->nullable();
|
||||
|
||||
// Distance and time
|
||||
$table->decimal('distance', 8, 2)->nullable();
|
||||
$table->string('distance_unit', 10)->default('km');
|
||||
$table->integer('estimated_duration')->nullable(); // in minutes
|
||||
$table->timestamp('estimated_pickup_time')->nullable();
|
||||
$table->timestamp('estimated_delivery_time')->nullable();
|
||||
|
||||
// Actual timestamps
|
||||
$table->timestamp('food_ready_at')->nullable();
|
||||
$table->timestamp('rider_assigned_at')->nullable();
|
||||
$table->timestamp('rider_accepted_at')->nullable();
|
||||
$table->timestamp('rider_at_restaurant_at')->nullable();
|
||||
$table->timestamp('picked_up_at')->nullable();
|
||||
$table->timestamp('on_the_way_at')->nullable();
|
||||
$table->timestamp('arrived_at')->nullable();
|
||||
$table->timestamp('delivered_at')->nullable();
|
||||
$table->timestamp('cancelled_at')->nullable();
|
||||
$table->timestamp('failed_at')->nullable();
|
||||
|
||||
// Pricing
|
||||
$table->decimal('base_fare', 10, 2)->default(0);
|
||||
$table->decimal('distance_charge', 10, 2)->default(0);
|
||||
$table->decimal('surge_charge', 10, 2)->default(0);
|
||||
$table->decimal('surge_multiplier', 4, 2)->default(1.00);
|
||||
$table->decimal('peak_hour_charge', 10, 2)->default(0);
|
||||
$table->decimal('late_night_charge', 10, 2)->default(0);
|
||||
$table->decimal('small_order_fee', 10, 2)->default(0);
|
||||
$table->decimal('total_delivery_charge', 10, 2)->default(0);
|
||||
$table->json('charge_breakdown')->nullable();
|
||||
|
||||
// Tip
|
||||
$table->decimal('tip_amount', 10, 2)->default(0);
|
||||
$table->string('tip_type')->nullable(); // pre_delivery, post_delivery
|
||||
$table->timestamp('tip_paid_at')->nullable();
|
||||
|
||||
// Order value (for small order fee calculation)
|
||||
$table->decimal('order_value', 10, 2)->default(0);
|
||||
|
||||
// Cancellation
|
||||
$table->string('cancellation_reason')->nullable();
|
||||
$table->string('cancelled_by')->nullable();
|
||||
$table->text('cancellation_notes')->nullable();
|
||||
|
||||
// Failure
|
||||
$table->string('failure_reason')->nullable();
|
||||
$table->text('failure_notes')->nullable();
|
||||
|
||||
// Route data
|
||||
$table->text('route_polyline')->nullable();
|
||||
$table->json('route_data')->nullable();
|
||||
|
||||
// Assignment
|
||||
$table->unsignedTinyInteger('assignment_attempts')->default(0);
|
||||
$table->unsignedTinyInteger('reassignment_count')->default(0);
|
||||
$table->json('assignment_history')->nullable();
|
||||
|
||||
// Proof of delivery
|
||||
$table->string('delivery_photo')->nullable();
|
||||
$table->string('signature')->nullable();
|
||||
$table->string('recipient_name')->nullable();
|
||||
|
||||
// Customer communication
|
||||
$table->boolean('customer_notified')->default(false);
|
||||
$table->json('notification_log')->nullable();
|
||||
|
||||
// Priority
|
||||
$table->boolean('is_priority')->default(false);
|
||||
$table->boolean('is_scheduled')->default(false);
|
||||
$table->timestamp('scheduled_for')->nullable();
|
||||
|
||||
// Metadata
|
||||
$table->json('meta')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['status', 'created_at']);
|
||||
$table->index(['rider_id', 'status']);
|
||||
$table->index(['restaurant_id', 'status']);
|
||||
$table->index('tracking_code');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_deliveries');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_delivery_ratings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
$table->foreignId('delivery_id')->constrained('restaurant_deliveries')->cascadeOnDelete();
|
||||
$table->foreignId('rider_id')->constrained('restaurant_riders')->cascadeOnDelete();
|
||||
$table->foreignId('customer_id')->nullable()->index();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
|
||||
// Overall rating
|
||||
$table->unsignedTinyInteger('overall_rating'); // 1-5
|
||||
|
||||
// Category ratings
|
||||
$table->unsignedTinyInteger('speed_rating')->nullable();
|
||||
$table->unsignedTinyInteger('communication_rating')->nullable();
|
||||
$table->unsignedTinyInteger('food_condition_rating')->nullable();
|
||||
$table->unsignedTinyInteger('professionalism_rating')->nullable();
|
||||
|
||||
// Review
|
||||
$table->text('review')->nullable();
|
||||
$table->boolean('is_anonymous')->default(false);
|
||||
|
||||
// Tags (quick feedback)
|
||||
$table->json('tags')->nullable(); // ['friendly', 'fast', 'careful', 'late', 'rude']
|
||||
|
||||
// Restaurant can also rate rider
|
||||
$table->boolean('is_restaurant_rating')->default(false);
|
||||
|
||||
// Moderation
|
||||
$table->boolean('is_approved')->default(true);
|
||||
$table->boolean('is_featured')->default(false);
|
||||
$table->string('moderation_status')->default('approved'); // pending, approved, rejected
|
||||
$table->text('moderation_notes')->nullable();
|
||||
|
||||
// Rider response
|
||||
$table->text('rider_response')->nullable();
|
||||
$table->timestamp('rider_responded_at')->nullable();
|
||||
|
||||
// Helpful votes (if you want community feedback on reviews)
|
||||
$table->unsignedInteger('helpful_count')->default(0);
|
||||
$table->unsignedInteger('not_helpful_count')->default(0);
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['rider_id', 'created_at']);
|
||||
$table->index(['overall_rating']);
|
||||
$table->unique(['delivery_id', 'is_restaurant_rating'], 'deliv_rating_unique');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_delivery_ratings');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_delivery_tips', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
$table->foreignId('delivery_id')->constrained('restaurant_deliveries')->cascadeOnDelete();
|
||||
$table->foreignId('rider_id')->constrained('restaurant_riders')->cascadeOnDelete();
|
||||
$table->foreignId('customer_id')->nullable()->index();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
|
||||
// Tip details
|
||||
$table->decimal('amount', 10, 2);
|
||||
$table->string('currency', 3)->default('BDT');
|
||||
$table->enum('type', ['pre_delivery', 'post_delivery'])->default('pre_delivery');
|
||||
$table->enum('calculation_type', ['fixed', 'percentage'])->default('fixed');
|
||||
$table->decimal('percentage_value', 5, 2)->nullable(); // If percentage-based
|
||||
$table->decimal('order_value', 10, 2)->nullable(); // Order value for percentage calculation
|
||||
|
||||
// Payment
|
||||
$table->string('payment_status')->default('pending'); // pending, captured, transferred, failed
|
||||
$table->string('payment_method')->nullable();
|
||||
$table->string('payment_reference')->nullable();
|
||||
$table->timestamp('paid_at')->nullable();
|
||||
|
||||
// Distribution
|
||||
$table->decimal('rider_amount', 10, 2); // Amount rider receives
|
||||
$table->decimal('platform_amount', 10, 2)->default(0); // Platform fee if any
|
||||
$table->decimal('rider_share_percentage', 5, 2)->default(100);
|
||||
|
||||
// Transferred to rider
|
||||
$table->boolean('is_transferred')->default(false);
|
||||
$table->timestamp('transferred_at')->nullable();
|
||||
$table->foreignId('payout_id')->nullable();
|
||||
|
||||
// Message
|
||||
$table->string('message')->nullable(); // Optional message from customer
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['rider_id', 'is_transferred']);
|
||||
$table->index(['payment_status']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_delivery_tips');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_rider_earnings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
$table->foreignId('rider_id')->constrained('restaurant_riders')->cascadeOnDelete();
|
||||
$table->foreignId('delivery_id')->nullable()->constrained('restaurant_deliveries')->nullOnDelete();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
|
||||
// Earning type
|
||||
$table->enum('type', [
|
||||
'delivery', // Regular delivery earning
|
||||
'tip', // Tip from customer
|
||||
'bonus', // Any bonus
|
||||
'penalty', // Penalty/deduction
|
||||
'adjustment', // Manual adjustment
|
||||
'incentive', // Special incentive
|
||||
])->default('delivery');
|
||||
|
||||
// Sub-type for bonuses/penalties
|
||||
$table->string('sub_type')->nullable(); // peak_hour, rain, consecutive, rating, cancellation, late
|
||||
|
||||
// Amount details
|
||||
$table->decimal('gross_amount', 10, 2);
|
||||
$table->decimal('platform_fee', 10, 2)->default(0);
|
||||
$table->decimal('tax', 10, 2)->default(0);
|
||||
$table->decimal('deductions', 10, 2)->default(0);
|
||||
$table->decimal('net_amount', 10, 2);
|
||||
$table->string('currency', 3)->default('BDT');
|
||||
|
||||
// Calculation details
|
||||
$table->json('calculation_breakdown')->nullable();
|
||||
|
||||
// Description
|
||||
$table->string('description')->nullable();
|
||||
|
||||
// Status
|
||||
$table->string('status')->default('pending'); // pending, confirmed, paid, cancelled
|
||||
$table->timestamp('confirmed_at')->nullable();
|
||||
|
||||
// Payout
|
||||
$table->foreignId('payout_id')->nullable();
|
||||
$table->boolean('is_paid')->default(false);
|
||||
$table->timestamp('paid_at')->nullable();
|
||||
|
||||
// For weekly/daily reporting
|
||||
$table->date('earning_date');
|
||||
$table->unsignedTinyInteger('earning_week')->nullable();
|
||||
$table->unsignedTinyInteger('earning_month')->nullable();
|
||||
$table->unsignedSmallInteger('earning_year')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['rider_id', 'status', 'earning_date']);
|
||||
$table->index(['rider_id', 'type']);
|
||||
$table->index(['is_paid', 'status']);
|
||||
$table->index(['earning_date']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_rider_earnings');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_rider_payouts', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
$table->string('payout_number')->unique();
|
||||
$table->foreignId('rider_id')->constrained('restaurant_riders')->cascadeOnDelete();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
|
||||
// Period
|
||||
$table->date('period_start');
|
||||
$table->date('period_end');
|
||||
$table->string('period_type')->default('weekly'); // daily, weekly, monthly
|
||||
|
||||
// Amount breakdown
|
||||
$table->decimal('total_deliveries_amount', 12, 2)->default(0);
|
||||
$table->decimal('total_tips_amount', 12, 2)->default(0);
|
||||
$table->decimal('total_bonuses_amount', 12, 2)->default(0);
|
||||
$table->decimal('total_penalties_amount', 12, 2)->default(0);
|
||||
$table->decimal('total_adjustments_amount', 12, 2)->default(0);
|
||||
$table->decimal('gross_amount', 12, 2);
|
||||
$table->decimal('platform_fees', 12, 2)->default(0);
|
||||
$table->decimal('tax_deductions', 12, 2)->default(0);
|
||||
$table->decimal('other_deductions', 12, 2)->default(0);
|
||||
$table->decimal('net_amount', 12, 2);
|
||||
$table->string('currency', 3)->default('BDT');
|
||||
|
||||
// Stats
|
||||
$table->unsignedInteger('total_deliveries')->default(0);
|
||||
$table->unsignedInteger('total_tips_count')->default(0);
|
||||
$table->unsignedInteger('total_bonuses_count')->default(0);
|
||||
$table->unsignedInteger('total_penalties_count')->default(0);
|
||||
|
||||
// Status
|
||||
$table->string('status')->default('pending'); // pending, processing, completed, failed, cancelled
|
||||
|
||||
// Payment details
|
||||
$table->string('payment_method')->nullable(); // bank_transfer, bkash, nagad, rocket, cash
|
||||
$table->string('payment_reference')->nullable();
|
||||
$table->json('payment_details')->nullable();
|
||||
/*
|
||||
Example:
|
||||
{
|
||||
"bank_name": "Brac Bank",
|
||||
"account_number": "****1234",
|
||||
"transaction_id": "TXN123456"
|
||||
}
|
||||
*/
|
||||
|
||||
// Timestamps
|
||||
$table->timestamp('processed_at')->nullable();
|
||||
$table->timestamp('paid_at')->nullable();
|
||||
$table->timestamp('failed_at')->nullable();
|
||||
|
||||
// Failure handling
|
||||
$table->string('failure_reason')->nullable();
|
||||
$table->unsignedTinyInteger('retry_count')->default(0);
|
||||
|
||||
// Approval
|
||||
$table->foreignId('approved_by')->nullable();
|
||||
$table->timestamp('approved_at')->nullable();
|
||||
$table->foreignId('processed_by')->nullable();
|
||||
|
||||
// Notes
|
||||
$table->text('notes')->nullable();
|
||||
$table->json('meta')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['rider_id', 'status']);
|
||||
$table->index(['status', 'created_at']);
|
||||
$table->index(['period_start', 'period_end']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_rider_payouts');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_rider_bonuses', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
|
||||
// Bonus details
|
||||
$table->string('name');
|
||||
$table->string('code')->unique();
|
||||
$table->text('description')->nullable();
|
||||
$table->enum('type', [
|
||||
'peak_hour',
|
||||
'rain',
|
||||
'consecutive',
|
||||
'rating',
|
||||
'weekly_target',
|
||||
'monthly_target',
|
||||
'referral',
|
||||
'special',
|
||||
'first_delivery',
|
||||
'new_area',
|
||||
]);
|
||||
|
||||
// Amount
|
||||
$table->enum('calculation_type', ['fixed', 'percentage', 'per_delivery', 'per_km'])->default('fixed');
|
||||
$table->decimal('amount', 10, 2);
|
||||
|
||||
// Conditions
|
||||
$table->json('conditions')->nullable();
|
||||
/*
|
||||
Example conditions:
|
||||
{
|
||||
"min_deliveries": 5,
|
||||
"min_rating": 4.8,
|
||||
"time_window": {"start": "12:00", "end": "14:00"},
|
||||
"weather_condition": "rain",
|
||||
"consecutive_count": 5,
|
||||
"target_deliveries": 50
|
||||
}
|
||||
*/
|
||||
|
||||
// Validity
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->date('valid_from')->nullable();
|
||||
$table->date('valid_until')->nullable();
|
||||
$table->json('valid_days')->nullable(); // Specific days of week
|
||||
|
||||
// Limits
|
||||
$table->unsignedInteger('max_uses_total')->nullable();
|
||||
$table->unsignedInteger('max_uses_per_rider')->nullable();
|
||||
$table->unsignedInteger('max_uses_per_day')->nullable();
|
||||
$table->unsignedInteger('current_uses')->default(0);
|
||||
|
||||
// Targeting
|
||||
$table->json('applicable_zones')->nullable();
|
||||
$table->json('applicable_rider_types')->nullable();
|
||||
$table->decimal('min_rider_rating', 3, 2)->nullable();
|
||||
|
||||
// Stacking
|
||||
$table->boolean('is_stackable')->default(false);
|
||||
$table->json('excluded_bonuses')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['type', 'is_active']);
|
||||
$table->index(['valid_from', 'valid_until']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_rider_bonuses');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_delivery_assignments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('uuid')->unique();
|
||||
$table->foreignId('delivery_id')->constrained('restaurant_deliveries')->cascadeOnDelete();
|
||||
$table->foreignId('rider_id')->constrained('restaurant_riders')->cascadeOnDelete();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
|
||||
// Assignment details
|
||||
$table->string('status')->default('pending'); // pending, accepted, rejected, expired, cancelled
|
||||
$table->unsignedTinyInteger('attempt_number')->default(1);
|
||||
|
||||
// Assignment method
|
||||
$table->enum('assignment_type', ['auto', 'manual', 'broadcast'])->default('auto');
|
||||
$table->foreignId('assigned_by')->nullable(); // User who assigned (for manual)
|
||||
|
||||
// Scoring (for auto-assignment)
|
||||
$table->decimal('score', 8, 2)->nullable();
|
||||
$table->json('score_breakdown')->nullable();
|
||||
/*
|
||||
Example:
|
||||
{
|
||||
"distance_score": 35,
|
||||
"rating_score": 23,
|
||||
"acceptance_rate_score": 14,
|
||||
"current_orders_score": 8,
|
||||
"experience_score": 9,
|
||||
"total": 89
|
||||
}
|
||||
*/
|
||||
|
||||
// Distance at time of assignment
|
||||
$table->decimal('distance_to_restaurant', 8, 2)->nullable();
|
||||
$table->integer('estimated_arrival_time')->nullable(); // minutes
|
||||
|
||||
// Response
|
||||
$table->timestamp('notified_at')->nullable();
|
||||
$table->timestamp('responded_at')->nullable();
|
||||
$table->timestamp('expires_at')->nullable();
|
||||
$table->string('rejection_reason')->nullable();
|
||||
$table->text('rejection_notes')->nullable();
|
||||
|
||||
// Location at assignment
|
||||
$table->decimal('rider_latitude', 10, 7)->nullable();
|
||||
$table->decimal('rider_longitude', 10, 7)->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['delivery_id', 'status']);
|
||||
$table->index(['rider_id', 'status']);
|
||||
$table->index(['status', 'expires_at']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_delivery_assignments');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_rider_location_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
$table->foreignId('rider_id')->constrained('restaurant_riders')->cascadeOnDelete();
|
||||
$table->foreignId('delivery_id')->nullable()->constrained('restaurant_deliveries')->nullOnDelete();
|
||||
|
||||
// Location
|
||||
$table->decimal('latitude', 10, 7);
|
||||
$table->decimal('longitude', 10, 7);
|
||||
$table->float('speed')->nullable(); // km/h
|
||||
$table->float('bearing')->nullable(); // degrees
|
||||
$table->float('accuracy')->nullable(); // meters
|
||||
$table->float('altitude')->nullable(); // meters
|
||||
|
||||
// Battery and device info
|
||||
$table->unsignedTinyInteger('battery_level')->nullable();
|
||||
$table->boolean('is_charging')->nullable();
|
||||
$table->string('network_type')->nullable(); // wifi, 4g, 3g
|
||||
|
||||
// Source
|
||||
$table->string('source')->default('app'); // app, manual, api
|
||||
|
||||
$table->timestamp('recorded_at');
|
||||
$table->timestamps();
|
||||
|
||||
// Indexes for efficient querying
|
||||
$table->index(['rider_id', 'recorded_at']);
|
||||
$table->index(['delivery_id', 'recorded_at']);
|
||||
$table->index('recorded_at');
|
||||
|
||||
// Partitioning hint - location logs can grow very large
|
||||
// Consider partitioning by date in production
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_rider_location_logs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('restaurant_delivery_status_history', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('restaurant_id')->nullable()->index();
|
||||
$table->foreignId('delivery_id')->constrained('restaurant_deliveries')->cascadeOnDelete();
|
||||
$table->foreignId('rider_id')->nullable()->constrained('restaurant_riders')->nullOnDelete();
|
||||
|
||||
// Status change
|
||||
$table->string('from_status')->nullable();
|
||||
$table->string('to_status');
|
||||
|
||||
// Who made the change
|
||||
$table->string('changed_by_type')->nullable(); // rider, customer, restaurant, system, admin
|
||||
$table->unsignedBigInteger('changed_by_id')->nullable();
|
||||
|
||||
// Location at status change
|
||||
$table->decimal('latitude', 10, 7)->nullable();
|
||||
$table->decimal('longitude', 10, 7)->nullable();
|
||||
|
||||
// Additional data
|
||||
$table->text('notes')->nullable();
|
||||
$table->json('meta')->nullable();
|
||||
|
||||
// Timing
|
||||
$table->integer('duration_from_previous')->nullable(); // seconds from previous status
|
||||
$table->integer('duration_from_start')->nullable(); // seconds from delivery creation
|
||||
|
||||
$table->timestamp('changed_at');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['delivery_id', 'changed_at']);
|
||||
$table->index('to_status');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('restaurant_delivery_status_history');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\RestaurantDelivery\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class RestaurantDeliveryDatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$this->call([
|
||||
RestaurantDeliveryZoneSeeder::class,
|
||||
RestaurantRiderSeeder::class,
|
||||
RestaurantZonePricingRuleSeeder::class,
|
||||
RestaurantDeliverySeeder::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\RestaurantDelivery\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Modules\Restaurant\Models\Order;
|
||||
|
||||
class RestaurantDeliverySeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$deliveries = [
|
||||
|
||||
// =========================
|
||||
// Delivery 1 – In Progress
|
||||
// =========================
|
||||
[
|
||||
'uuid' => Str::uuid(),
|
||||
'tracking_code' => 'TRKBD10001',
|
||||
'restaurant_id' => 1,
|
||||
'rider_id' => 1,
|
||||
'zone_id' => 1,
|
||||
|
||||
// Polymorphic order
|
||||
'orderable_id' => 10,
|
||||
'orderable_type' => Order::class,
|
||||
|
||||
'status' => 'on_the_way',
|
||||
'previous_status' => 'picked_up',
|
||||
'status_changed_at' => now()->subMinutes(5),
|
||||
|
||||
'restaurant_name' => 'Kacchi Bhai Dhanmondi',
|
||||
'pickup_address' => 'Dhanmondi 32, Dhaka',
|
||||
'pickup_latitude' => 23.7461,
|
||||
'pickup_longitude' => 90.3742,
|
||||
'pickup_contact_name' => 'Restaurant Manager',
|
||||
'pickup_contact_phone' => '01711000000',
|
||||
|
||||
'customer_name' => 'Rahim Uddin',
|
||||
'drop_address' => 'Gulshan 1, Dhaka',
|
||||
'drop_latitude' => 23.7930,
|
||||
'drop_longitude' => 90.4043,
|
||||
'drop_contact_name' => 'Rahim',
|
||||
'drop_contact_phone' => '01819000000',
|
||||
'drop_floor' => '5th',
|
||||
'drop_apartment' => 'A5',
|
||||
|
||||
'distance' => 5.8,
|
||||
'estimated_duration' => 28,
|
||||
|
||||
'base_fare' => 30,
|
||||
'distance_charge' => 46.4,
|
||||
'surge_charge' => 0,
|
||||
'total_delivery_charge' => 76.4,
|
||||
'charge_breakdown' => json_encode([
|
||||
'base' => 30,
|
||||
'distance' => 46.4,
|
||||
]),
|
||||
|
||||
'order_value' => 850,
|
||||
|
||||
'rider_assigned_at' => now()->subMinutes(25),
|
||||
'picked_up_at' => now()->subMinutes(10),
|
||||
'on_the_way_at' => now()->subMinutes(5),
|
||||
|
||||
'assignment_attempts' => 1,
|
||||
|
||||
'meta' => json_encode([
|
||||
'payment_mode' => 'cod',
|
||||
]),
|
||||
],
|
||||
|
||||
// =========================
|
||||
// Delivery 2 – Delivered
|
||||
// =========================
|
||||
[
|
||||
'uuid' => Str::uuid(),
|
||||
'tracking_code' => 'TRKBD10002',
|
||||
'restaurant_id' => 1,
|
||||
'rider_id' => 2,
|
||||
'zone_id' => 2,
|
||||
|
||||
'orderable_id' => 11,
|
||||
'orderable_type' => Order::class,
|
||||
|
||||
'status' => 'delivered',
|
||||
'previous_status' => 'arrived',
|
||||
'status_changed_at' => now()->subMinutes(2),
|
||||
|
||||
'restaurant_name' => 'Pizza Roma Gulshan',
|
||||
'pickup_address' => 'Gulshan 2 Circle, Dhaka',
|
||||
'pickup_latitude' => 23.7937,
|
||||
'pickup_longitude' => 90.4066,
|
||||
|
||||
'customer_name' => 'Karim Ahmed',
|
||||
'drop_address' => 'Banani DOHS, Dhaka',
|
||||
'drop_latitude' => 23.8103,
|
||||
'drop_longitude' => 90.4125,
|
||||
'drop_contact_phone' => '01715000000',
|
||||
|
||||
'distance' => 4.2,
|
||||
'estimated_duration' => 22,
|
||||
|
||||
'base_fare' => 40,
|
||||
'distance_charge' => 50.4,
|
||||
'surge_charge' => 15,
|
||||
'surge_multiplier' => 1.3,
|
||||
'total_delivery_charge' => 105.4,
|
||||
|
||||
'tip_amount' => 50,
|
||||
'tip_type' => 'post_delivery',
|
||||
'tip_paid_at' => now(),
|
||||
|
||||
'order_value' => 1200,
|
||||
|
||||
'rider_assigned_at' => now()->subMinutes(40),
|
||||
'picked_up_at' => now()->subMinutes(25),
|
||||
'delivered_at' => now()->subMinutes(2),
|
||||
|
||||
'delivery_photo' => 'deliveries/proof_10002.jpg',
|
||||
'recipient_name' => 'Karim Ahmed',
|
||||
|
||||
'customer_notified' => true,
|
||||
|
||||
'assignment_attempts' => 1,
|
||||
],
|
||||
|
||||
// =========================
|
||||
// Delivery 3 – Cancelled
|
||||
// =========================
|
||||
[
|
||||
'uuid' => Str::uuid(),
|
||||
'tracking_code' => 'TRKBD10003',
|
||||
'restaurant_id' => 1,
|
||||
'rider_id' => null,
|
||||
'zone_id' => 3,
|
||||
|
||||
'orderable_id' => 12,
|
||||
'orderable_type' => Order::class,
|
||||
|
||||
'status' => 'cancelled',
|
||||
'previous_status' => 'pending',
|
||||
'status_changed_at' => now()->subMinutes(15),
|
||||
|
||||
'restaurant_name' => 'Burger Express Mirpur',
|
||||
'pickup_address' => 'Mirpur 10, Dhaka',
|
||||
'pickup_latitude' => 23.8223,
|
||||
'pickup_longitude' => 90.3654,
|
||||
|
||||
'customer_name' => 'Sabbir Khan',
|
||||
'drop_address' => 'Mirpur 11, Dhaka',
|
||||
'drop_latitude' => 23.8300,
|
||||
'drop_longitude' => 90.3600,
|
||||
|
||||
'order_value' => 420,
|
||||
|
||||
'cancellation_reason' => 'Customer requested cancellation',
|
||||
'cancelled_by' => 'customer',
|
||||
'cancelled_at' => now()->subMinutes(15),
|
||||
|
||||
'assignment_attempts' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($deliveries as $delivery) {
|
||||
DB::table('restaurant_deliveries')->insert(array_merge(
|
||||
$delivery,
|
||||
[
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\RestaurantDelivery\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class RestaurantDeliveryZoneSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$zones = [
|
||||
[
|
||||
'restaurant_id' => 1,
|
||||
'uuid' => Str::uuid(),
|
||||
'name' => 'Dhanmondi Zone',
|
||||
'slug' => 'dhanmondi-zone',
|
||||
'description' => 'Delivery zone covering Dhanmondi area',
|
||||
'color' => '#3B82F6',
|
||||
'coordinates' => json_encode([
|
||||
[23.7461, 90.3742],
|
||||
[23.7485, 90.3810],
|
||||
[23.7428, 90.3852],
|
||||
[23.7395, 90.3770],
|
||||
[23.7461, 90.3742],
|
||||
]),
|
||||
'min_lat' => 23.7395,
|
||||
'max_lat' => 23.7485,
|
||||
'min_lng' => 90.3742,
|
||||
'max_lng' => 90.3852,
|
||||
'priority' => 1,
|
||||
'is_active' => true,
|
||||
'is_default' => true,
|
||||
'max_delivery_distance' => 5.00,
|
||||
'operating_hours' => json_encode([
|
||||
'open' => '10:00',
|
||||
'close' => '23:00',
|
||||
]),
|
||||
],
|
||||
[
|
||||
'restaurant_id' => 1,
|
||||
'uuid' => Str::uuid(),
|
||||
'name' => 'Gulshan Zone',
|
||||
'slug' => 'gulshan-zone',
|
||||
'description' => 'Delivery zone covering Gulshan area',
|
||||
'color' => '#22C55E',
|
||||
'coordinates' => json_encode([
|
||||
[23.7930, 90.4043],
|
||||
[23.7965, 90.4108],
|
||||
[23.7892, 90.4151],
|
||||
[23.7850, 90.4082],
|
||||
[23.7930, 90.4043],
|
||||
]),
|
||||
'min_lat' => 23.7850,
|
||||
'max_lat' => 23.7965,
|
||||
'min_lng' => 90.4043,
|
||||
'max_lng' => 90.4151,
|
||||
'priority' => 2,
|
||||
'is_active' => true,
|
||||
'is_default' => false,
|
||||
'max_delivery_distance' => 6.00,
|
||||
'operating_hours' => json_encode([
|
||||
'open' => '09:00',
|
||||
'close' => '22:30',
|
||||
]),
|
||||
],
|
||||
[
|
||||
'restaurant_id' => 1,
|
||||
'uuid' => Str::uuid(),
|
||||
'name' => 'Mirpur Zone',
|
||||
'slug' => 'mirpur-zone',
|
||||
'description' => 'Delivery zone covering Mirpur area',
|
||||
'color' => '#F97316',
|
||||
'coordinates' => json_encode([
|
||||
[23.8223, 90.3654],
|
||||
[23.8280, 90.3725],
|
||||
[23.8190, 90.3780],
|
||||
[23.8135, 90.3698],
|
||||
[23.8223, 90.3654],
|
||||
]),
|
||||
'min_lat' => 23.8135,
|
||||
'max_lat' => 23.8280,
|
||||
'min_lng' => 90.3654,
|
||||
'max_lng' => 90.3780,
|
||||
'priority' => 3,
|
||||
'is_active' => true,
|
||||
'is_default' => false,
|
||||
'max_delivery_distance' => 7.00,
|
||||
'operating_hours' => json_encode([
|
||||
'open' => '10:00',
|
||||
'close' => '22:00',
|
||||
]),
|
||||
],
|
||||
[
|
||||
'restaurant_id' => 1,
|
||||
'uuid' => Str::uuid(),
|
||||
'name' => 'Uttara Zone',
|
||||
'slug' => 'uttara-zone',
|
||||
'description' => 'Delivery zone covering Uttara area',
|
||||
'color' => '#A855F7',
|
||||
'coordinates' => json_encode([
|
||||
[23.8759, 90.3795],
|
||||
[23.8812, 90.3878],
|
||||
[23.8720, 90.3932],
|
||||
[23.8671, 90.3841],
|
||||
[23.8759, 90.3795],
|
||||
]),
|
||||
'min_lat' => 23.8671,
|
||||
'max_lat' => 23.8812,
|
||||
'min_lng' => 90.3795,
|
||||
'max_lng' => 90.3932,
|
||||
'priority' => 4,
|
||||
'is_active' => true,
|
||||
'is_default' => false,
|
||||
'max_delivery_distance' => 8.00,
|
||||
'operating_hours' => json_encode([
|
||||
'open' => '09:30',
|
||||
'close' => '23:30',
|
||||
]),
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($zones as $zone) {
|
||||
DB::table('restaurant_delivery_zones')->insert(array_merge($zone, [
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\RestaurantDelivery\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class RestaurantRiderSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$riders = [
|
||||
// ======================
|
||||
// Rider 1 – Motorcycle (Active)
|
||||
// ======================
|
||||
[
|
||||
'uuid' => Str::uuid(),
|
||||
'restaurant_id' => 1,
|
||||
'user_id' => 23,
|
||||
|
||||
'first_name' => 'Rakib',
|
||||
'last_name' => 'Hossain',
|
||||
'phone' => '01710000001',
|
||||
'email' => 'rakib.rider@gmail.com',
|
||||
'photo' => null,
|
||||
'date_of_birth' => '1998-04-15',
|
||||
'national_id' => '19982654789012345',
|
||||
'emergency_contact' => '01790000001',
|
||||
|
||||
'type' => 'freelance',
|
||||
'status' => 'active',
|
||||
|
||||
'vehicle_type' => 'motorcycle',
|
||||
'vehicle_number' => 'DHAKA-METRO-LA-123456',
|
||||
'vehicle_model' => 'Bajaj Discover 125',
|
||||
'vehicle_color' => 'Black',
|
||||
'license_number' => 'DL-45879632',
|
||||
'license_expiry' => '2027-06-30',
|
||||
|
||||
'is_verified' => true,
|
||||
'verified_at' => now(),
|
||||
'verified_by' => 'admin',
|
||||
'verification_documents' => json_encode([
|
||||
'nid' => 'nid_rakib.jpg',
|
||||
'license' => 'license_rakib.jpg',
|
||||
]),
|
||||
|
||||
'commission_type' => 'percentage',
|
||||
'commission_rate' => 70,
|
||||
|
||||
'current_latitude' => 23.7461,
|
||||
'current_longitude' => 90.3742,
|
||||
'last_location_update' => now(),
|
||||
|
||||
'rating' => 4.85,
|
||||
'rating_count' => 124,
|
||||
'total_deliveries' => 320,
|
||||
'successful_deliveries' => 305,
|
||||
'cancelled_deliveries' => 10,
|
||||
'failed_deliveries' => 5,
|
||||
'acceptance_rate' => 95.00,
|
||||
'completion_rate' => 96.50,
|
||||
|
||||
'is_online' => true,
|
||||
'last_online_at' => now(),
|
||||
|
||||
'bank_name' => 'bKash',
|
||||
'mobile_wallet_provider' => 'bKash',
|
||||
'mobile_wallet_number' => '01710000001',
|
||||
|
||||
'assigned_zones' => json_encode([1, 2]),
|
||||
'meta' => json_encode(['shift' => 'day']),
|
||||
],
|
||||
|
||||
// ======================
|
||||
// Rider 2 – Bicycle (Budget)
|
||||
// ======================
|
||||
[
|
||||
'uuid' => Str::uuid(),
|
||||
'restaurant_id' => 1,
|
||||
'user_id' => 24,
|
||||
|
||||
'first_name' => 'Sajid',
|
||||
'last_name' => 'Ahmed',
|
||||
'phone' => '01820000002',
|
||||
'email' => null,
|
||||
|
||||
'type' => 'freelance',
|
||||
'status' => 'active',
|
||||
|
||||
'vehicle_type' => 'bicycle',
|
||||
|
||||
'is_verified' => true,
|
||||
'verified_at' => now(),
|
||||
'verified_by' => 'admin',
|
||||
|
||||
'commission_type' => 'fixed',
|
||||
'commission_rate' => 50,
|
||||
|
||||
'current_latitude' => 23.8223,
|
||||
'current_longitude' => 90.3654,
|
||||
'last_location_update' => now(),
|
||||
|
||||
'rating' => 4.60,
|
||||
'rating_count' => 52,
|
||||
'total_deliveries' => 140,
|
||||
'successful_deliveries' => 135,
|
||||
'cancelled_deliveries' => 3,
|
||||
'failed_deliveries' => 2,
|
||||
|
||||
'is_online' => true,
|
||||
'last_online_at' => now(),
|
||||
|
||||
'assigned_zones' => json_encode([3]),
|
||||
'meta' => json_encode(['shift' => 'morning']),
|
||||
],
|
||||
|
||||
// ======================
|
||||
// Rider 3 – Car (Premium / Gulshan)
|
||||
// ======================
|
||||
[
|
||||
'uuid' => Str::uuid(),
|
||||
'restaurant_id' => 1,
|
||||
'user_id' => null,
|
||||
|
||||
'first_name' => 'Mahmud',
|
||||
'last_name' => 'Khan',
|
||||
'phone' => '01930000003',
|
||||
'email' => 'mahmud.khan@gmail.com',
|
||||
|
||||
'type' => 'internal',
|
||||
'status' => 'active',
|
||||
|
||||
'vehicle_type' => 'car',
|
||||
'vehicle_number' => 'DHAKA-METRO-GA-987654',
|
||||
'vehicle_model' => 'Toyota Axio',
|
||||
'vehicle_color' => 'White',
|
||||
|
||||
'is_verified' => true,
|
||||
'verified_at' => now(),
|
||||
'verified_by' => 'super_admin',
|
||||
|
||||
'commission_type' => 'hybrid',
|
||||
'commission_rate' => 60,
|
||||
'base_commission' => 40,
|
||||
'per_km_rate' => 6,
|
||||
|
||||
'current_latitude' => 23.7930,
|
||||
'current_longitude' => 90.4043,
|
||||
'last_location_update' => now(),
|
||||
|
||||
'rating' => 4.95,
|
||||
'rating_count' => 210,
|
||||
'total_deliveries' => 410,
|
||||
'successful_deliveries' => 405,
|
||||
|
||||
'is_online' => false,
|
||||
'went_offline_at' => now()->subHours(2),
|
||||
|
||||
'bank_name' => 'Dutch Bangla Bank',
|
||||
'bank_account_name' => 'Mahmud Khan',
|
||||
'bank_account_number' => '1234567890',
|
||||
|
||||
'assigned_zones' => json_encode([2, 4]),
|
||||
'meta' => json_encode(['vehicle_class' => 'premium']),
|
||||
],
|
||||
|
||||
// ======================
|
||||
// Rider 4 – Pending Verification
|
||||
// ======================
|
||||
[
|
||||
'uuid' => Str::uuid(),
|
||||
'restaurant_id' => 1,
|
||||
'user_id' => null,
|
||||
|
||||
'first_name' => 'Arif',
|
||||
'last_name' => 'Hasan',
|
||||
'phone' => '01640000004',
|
||||
|
||||
'type' => 'third_party',
|
||||
'status' => 'pending',
|
||||
|
||||
'vehicle_type' => 'motorcycle',
|
||||
|
||||
'is_verified' => false,
|
||||
|
||||
'commission_type' => 'percentage',
|
||||
'commission_rate' => 65,
|
||||
|
||||
'rating' => 5.00,
|
||||
'rating_count' => 0,
|
||||
|
||||
'is_online' => false,
|
||||
|
||||
'assigned_zones' => json_encode([1]),
|
||||
'meta' => json_encode(['note' => 'Awaiting documents']),
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($riders as $rider) {
|
||||
DB::table('restaurant_riders')->insert(array_merge(
|
||||
$rider,
|
||||
[
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\RestaurantDelivery\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class RestaurantZonePricingRuleSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$rules = [
|
||||
|
||||
// =========================
|
||||
// Dhanmondi Zone (Zone ID 1)
|
||||
// =========================
|
||||
[
|
||||
'restaurant_id' => 1,
|
||||
'zone_id' => 1,
|
||||
'uuid' => Str::uuid(),
|
||||
'name' => 'Dhanmondi Standard Pricing',
|
||||
'priority' => 1,
|
||||
'is_active' => true,
|
||||
'base_fare' => 30,
|
||||
'minimum_fare' => 30,
|
||||
'per_km_charge' => 8,
|
||||
'free_distance' => 1,
|
||||
'max_distance' => 8,
|
||||
'surge_enabled' => false,
|
||||
'surge_multiplier' => 1.00,
|
||||
'conditions' => null,
|
||||
'valid_from' => null,
|
||||
'valid_until' => null,
|
||||
'valid_days' => null,
|
||||
],
|
||||
[
|
||||
'restaurant_id' => 1,
|
||||
'zone_id' => 1,
|
||||
'uuid' => Str::uuid(),
|
||||
'name' => 'Dhanmondi Peak Hour Surge',
|
||||
'priority' => 2,
|
||||
'is_active' => true,
|
||||
'base_fare' => 35,
|
||||
'minimum_fare' => 40,
|
||||
'per_km_charge' => 9,
|
||||
'free_distance' => 0,
|
||||
'max_distance' => null,
|
||||
'surge_enabled' => true,
|
||||
'surge_multiplier' => 1.30,
|
||||
'conditions' => json_encode([
|
||||
'type' => 'peak_hour',
|
||||
'note' => 'Evening rush',
|
||||
]),
|
||||
'valid_from' => '18:00:00',
|
||||
'valid_until' => '22:00:00',
|
||||
'valid_days' => 62, // Mon–Thu, Sun
|
||||
],
|
||||
|
||||
// ======================
|
||||
// Gulshan Zone (Zone ID 2)
|
||||
// ======================
|
||||
[
|
||||
'restaurant_id' => 1,
|
||||
'zone_id' => 2,
|
||||
'uuid' => Str::uuid(),
|
||||
'name' => 'Gulshan Standard Pricing',
|
||||
'priority' => 1,
|
||||
'is_active' => true,
|
||||
'base_fare' => 40,
|
||||
'minimum_fare' => 50,
|
||||
'per_km_charge' => 12,
|
||||
'free_distance' => 0,
|
||||
'max_distance' => 10,
|
||||
'surge_enabled' => false,
|
||||
'surge_multiplier' => 1.00,
|
||||
'conditions' => null,
|
||||
'valid_from' => null,
|
||||
'valid_until' => null,
|
||||
'valid_days' => null,
|
||||
],
|
||||
[
|
||||
'restaurant_id' => 1,
|
||||
'zone_id' => 2,
|
||||
'uuid' => Str::uuid(),
|
||||
'name' => 'Gulshan Weekend Surge',
|
||||
'priority' => 2,
|
||||
'is_active' => true,
|
||||
'base_fare' => 45,
|
||||
'minimum_fare' => 60,
|
||||
'per_km_charge' => 14,
|
||||
'free_distance' => 0,
|
||||
'max_distance' => null,
|
||||
'surge_enabled' => true,
|
||||
'surge_multiplier' => 1.50,
|
||||
'conditions' => json_encode([
|
||||
'type' => 'weekend',
|
||||
'note' => 'Friday & Saturday',
|
||||
]),
|
||||
'valid_from' => '12:00:00',
|
||||
'valid_until' => '23:59:59',
|
||||
'valid_days' => 96, // Fri + Sat
|
||||
],
|
||||
|
||||
// ======================
|
||||
// Mirpur Zone (Zone ID 3)
|
||||
// ======================
|
||||
[
|
||||
'restaurant_id' => 1,
|
||||
'zone_id' => 3,
|
||||
'uuid' => Str::uuid(),
|
||||
'name' => 'Mirpur Budget Pricing',
|
||||
'priority' => 1,
|
||||
'is_active' => true,
|
||||
'base_fare' => 25,
|
||||
'minimum_fare' => 30,
|
||||
'per_km_charge' => 7,
|
||||
'free_distance' => 1.5,
|
||||
'max_distance' => 7,
|
||||
'surge_enabled' => false,
|
||||
'surge_multiplier' => 1.00,
|
||||
'conditions' => null,
|
||||
'valid_from' => null,
|
||||
'valid_until' => null,
|
||||
'valid_days' => null,
|
||||
],
|
||||
|
||||
// ======================
|
||||
// Uttara Zone (Zone ID 4)
|
||||
// ======================
|
||||
[
|
||||
'restaurant_id' => 1,
|
||||
'zone_id' => 4,
|
||||
'uuid' => Str::uuid(),
|
||||
'name' => 'Uttara Long Distance Pricing',
|
||||
'priority' => 1,
|
||||
'is_active' => true,
|
||||
'base_fare' => 35,
|
||||
'minimum_fare' => 40,
|
||||
'per_km_charge' => 9,
|
||||
'free_distance' => 1,
|
||||
'max_distance' => 12,
|
||||
'surge_enabled' => false,
|
||||
'surge_multiplier' => 1.00,
|
||||
'conditions' => null,
|
||||
'valid_from' => null,
|
||||
'valid_until' => null,
|
||||
'valid_days' => null,
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
DB::table('restaurant_zone_pricing_rules')->insert(array_merge(
|
||||
$rule,
|
||||
[
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user