diff --git a/backend/app/Http/Controllers/CampaignController.php b/backend/app/Http/Controllers/CampaignController.php new file mode 100644 index 0000000..df74695 --- /dev/null +++ b/backend/app/Http/Controllers/CampaignController.php @@ -0,0 +1,39 @@ +validated())); + } + + public function show(Campaign $campaign) + { + return new CampaignResource($campaign); + } + + public function update(CampaignRequest $request, Campaign $campaign) + { + $campaign->update($request->validated()); + + return new CampaignResource($campaign); + } + + public function destroy(Campaign $campaign) + { + $campaign->delete(); + + return response()->json(); + } +} diff --git a/backend/app/Http/Controllers/CouponController.php b/backend/app/Http/Controllers/CouponController.php new file mode 100644 index 0000000..4ce16c1 --- /dev/null +++ b/backend/app/Http/Controllers/CouponController.php @@ -0,0 +1,39 @@ +validated())); + } + + public function show(Coupon $coupon) + { + return new CouponResource($coupon); + } + + public function update(CouponRequest $request, Coupon $coupon) + { + $coupon->update($request->validated()); + + return new CouponResource($coupon); + } + + public function destroy(Coupon $coupon) + { + $coupon->delete(); + + return response()->json(); + } +} diff --git a/backend/app/Http/Requests/CampaignRequest.php b/backend/app/Http/Requests/CampaignRequest.php new file mode 100644 index 0000000..b72db2f --- /dev/null +++ b/backend/app/Http/Requests/CampaignRequest.php @@ -0,0 +1,29 @@ + ['required'], + 'discount_type_id' => ['required', 'exists:discount_types'], + 'discount_value' => ['required', 'numeric'], + 'max_discount' => ['nullable', 'numeric'], + 'min_order_value' => ['nullable', 'numeric'], + 'start_time' => ['required', 'date'], + 'end_time' => ['required', 'date'], + 'total_usage_limit' => ['nullable', 'integer'], + 'per_user_limit' => ['nullable', 'integer'], + 'campaign_status_id' => ['required', 'exists:campaign_statuses'], + ]; + } + + public function authorize(): bool + { + return true; + } +} diff --git a/backend/app/Http/Requests/CouponRequest.php b/backend/app/Http/Requests/CouponRequest.php new file mode 100644 index 0000000..41c3bd0 --- /dev/null +++ b/backend/app/Http/Requests/CouponRequest.php @@ -0,0 +1,21 @@ + ['required', 'exists:campaigns'], + 'code' => ['required'], + ]; + } + + public function authorize(): bool + { + return true; + } +} diff --git a/backend/app/Http/Resources/CampaignResource.php b/backend/app/Http/Resources/CampaignResource.php new file mode 100644 index 0000000..cf8e595 --- /dev/null +++ b/backend/app/Http/Resources/CampaignResource.php @@ -0,0 +1,31 @@ + $this->id, + 'name' => $this->name, + 'discount_value' => $this->dicount_value, + 'max_discount' => $this->max_discount, + 'min_order_value' => $this->min_order_value, + 'start_time' => $this->start_time, + 'end_time' => $this->end_time, + 'total_usage_limit' => $this->total_usage_limit, + 'per_user_limit' => $this->per_user_limit, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + + 'discount_type_id' => $this->discount_type_id, + 'campaign_status_id' => $this->campaign_status_id, + ]; + } +} diff --git a/backend/app/Http/Resources/CouponResource.php b/backend/app/Http/Resources/CouponResource.php new file mode 100644 index 0000000..a008fc2 --- /dev/null +++ b/backend/app/Http/Resources/CouponResource.php @@ -0,0 +1,25 @@ + $this->id, + 'code' => $this->code, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + + 'campaign_id' => $this->campaign_id, + + 'campaign' => new CampaignResource($this->whenLoaded('campaign')), + ]; + } +} diff --git a/backend/app/Models/Campaign.php b/backend/app/Models/Campaign.php new file mode 100644 index 0000000..023c326 --- /dev/null +++ b/backend/app/Models/Campaign.php @@ -0,0 +1,40 @@ +belongsTo(DiscountType::class); + } + + public function campaignStatus(): BelongsTo + { + return $this->belongsTo(CampaignStatus::class); + } + + protected function casts(): array + { + return [ + 'start_time' => 'datetime', + 'end_time' => 'datetime', + ]; + } +} diff --git a/backend/app/Models/CampaignStatus.php b/backend/app/Models/CampaignStatus.php new file mode 100644 index 0000000..89aa8ae --- /dev/null +++ b/backend/app/Models/CampaignStatus.php @@ -0,0 +1,12 @@ +belongsTo(Campaign::class); + } +} diff --git a/backend/app/Models/DiscountType.php b/backend/app/Models/DiscountType.php new file mode 100644 index 0000000..f2a8a05 --- /dev/null +++ b/backend/app/Models/DiscountType.php @@ -0,0 +1,12 @@ +belongsTo(User::class); + } + + public function coupon(): BelongsTo + { + return $this->belongsTo(Coupon::class); + } + + public function order(): BelongsTo + { + return $this->belongsTo(Order::class); + } +} diff --git a/backend/database/migrations/2026_03_25_123843_create_campaign_statuses_table.php b/backend/database/migrations/2026_03_25_123843_create_campaign_statuses_table.php new file mode 100644 index 0000000..9b2a001 --- /dev/null +++ b/backend/database/migrations/2026_03_25_123843_create_campaign_statuses_table.php @@ -0,0 +1,21 @@ +id(); + $table->string('value'); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('campaign_statuses'); + } +}; diff --git a/backend/database/migrations/2026_03_25_124113_create_discount_types_table.php b/backend/database/migrations/2026_03_25_124113_create_discount_types_table.php new file mode 100644 index 0000000..2522224 --- /dev/null +++ b/backend/database/migrations/2026_03_25_124113_create_discount_types_table.php @@ -0,0 +1,21 @@ +id(); + $table->string('value'); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('discount_types'); + } +}; diff --git a/backend/database/migrations/2026_03_25_124754_create_campaigns_table.php b/backend/database/migrations/2026_03_25_124754_create_campaigns_table.php new file mode 100644 index 0000000..2feeb7b --- /dev/null +++ b/backend/database/migrations/2026_03_25_124754_create_campaigns_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('name'); + $table->foreignId('discount_type_id'); + $table->float('discount_value'); + $table->float('max_discount')->nullable(); + $table->float('min_order_value')->nullable(); + $table->dateTime('start_time'); + $table->dateTime('end_time'); + $table->integer('total_usage_limit')->nullable(); + $table->integer('per_user_limit')->nullable(); + $table->foreignId('campaign_status_id'); + $table->timestamps(); + $table->index(['campaign_status_id', 'start_time', 'end_time'], 'campaign_validity_index'); + $table->index(['name']); + }); + } + + public function down(): void + { + Schema::dropIfExists('campaigns'); + } +}; diff --git a/backend/database/migrations/2026_03_25_125215_create_coupons_table.php b/backend/database/migrations/2026_03_25_125215_create_coupons_table.php new file mode 100644 index 0000000..ca3d01c --- /dev/null +++ b/backend/database/migrations/2026_03_25_125215_create_coupons_table.php @@ -0,0 +1,23 @@ +id(); + $table->foreignId('campaign_id'); + $table->string('code'); + $table->timestamps(); + $table->index(['code']); + }); + } + + public function down(): void + { + Schema::dropIfExists('coupons'); + } +}; diff --git a/backend/database/migrations/2026_03_25_125649_create_redemtion_logs_table.php b/backend/database/migrations/2026_03_25_125649_create_redemtion_logs_table.php new file mode 100644 index 0000000..8bdd33a --- /dev/null +++ b/backend/database/migrations/2026_03_25_125649_create_redemtion_logs_table.php @@ -0,0 +1,23 @@ +id(); + $table->foreignId('user_id'); + $table->foreignId('coupon_id'); + $table->foreignId('order_id'); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('redemption_logs'); + } +};