Overview
Seller packages enable you to monetize your multi-vendor marketplace by offering tiered subscription plans. Each package defines product upload limits, duration, and pricing for sellers.
Upload Limits Control how many products sellers can list based on their package
Duration-Based Set package validity periods in days
Online & Offline Accept both online payments and offline payment verification
Auto Unpublish Automatically unpublish products when packages expire
Model Structure
SellerPackage Model
The SellerPackage model manages subscription tiers:
class SellerPackage extends Model
{
protected $guarded = [];
public function getTranslation ( $field = '' , $lang = false ){
$lang = $lang == false ? App :: getLocale () : $lang ;
$seller_package_translation = $this -> hasMany ( SellerPackageTranslation :: class )
-> where ( 'lang' , $lang ) -> first ();
return $seller_package_translation != null ?
$seller_package_translation -> $field : $this -> $field ;
}
public function seller_package_translations (){
return $this -> hasMany ( SellerPackageTranslation :: class );
}
public function seller_package_payments ()
{
return $this -> hasMany ( SelllerPackagePayment :: class );
}
public function shop ()
{
return $this -> hasOne ( Shop :: class );
}
}
Key Fields:
name - Package name
amount - Package price
product_upload_limit - Maximum products allowed
duration - Package validity in days
logo - Package icon/logo
Creating Packages
Create seller packages with translations (app/Http/Controllers/SellerPackageController.php:52):
public function store ( Request $request )
{
$seller_package = new SellerPackage ;
$seller_package -> name = $request -> name ;
$seller_package -> amount = $request -> amount ;
$seller_package -> product_upload_limit = $request -> product_upload_limit ;
$seller_package -> duration = $request -> duration ;
$seller_package -> logo = $request -> logo ;
if ( $seller_package -> save ()) {
$seller_package_translation = SellerPackageTranslation :: firstOrNew ([
'lang' => env ( 'DEFAULT_LANGUAGE' ),
'seller_package_id' => $seller_package -> id
]);
$seller_package_translation -> name = $request -> name ;
$seller_package_translation -> save ();
flash ( translate ( 'Package has been inserted successfully' )) -> success ();
return redirect () -> route ( 'seller_packages.index' );
}
}
Package Purchase Flow
Online Payment
Select Package
Seller chooses a package from the available options
Choose Payment Method
Select payment gateway (PayPal, Stripe, etc.)
Process Payment
Payment is processed through the selected gateway
Update Shop Limits
Product upload limit and expiry date are updated
Record Payment
Payment history is stored for reference
Implementation (app/Http/Controllers/SellerPackageController.php:160):
public function purchase_package ( Request $request )
{
$data [ 'seller_package_id' ] = $request -> seller_package_id ;
$data [ 'payment_method' ] = $request -> payment_option ;
$request -> session () -> put ( 'payment_type' , 'seller_package_payment' );
$request -> session () -> put ( 'payment_data' , $data );
$seller_package = SellerPackage :: findOrFail (
Session :: get ( 'payment_data' )[ 'seller_package_id' ]
);
// Free package
if ( $seller_package -> amount == 0 ) {
return $this -> purchase_payment_done (
Session :: get ( 'payment_data' ), null
);
}
// Check downgrade restriction
elseif ( Auth :: user () -> shop -> seller_package != null &&
$seller_package -> product_upload_limit <
Auth :: user () -> shop -> seller_package -> product_upload_limit ) {
flash ( translate ( 'You have more uploaded products than this package limit. You need to remove excessive products to downgrade.' )) -> warning ();
return back ();
}
$decorator = __NAMESPACE__ . ' \\ Payment \\ ' .
str_replace ( ' ' , '' , ucwords ( str_replace ( '_' , ' ' , $request -> payment_option ))) .
"Controller" ;
if ( class_exists ( $decorator )) {
return ( new $decorator ) -> pay ( $request );
}
}
Payment Completion
After successful payment (app/Http/Controllers/SellerPackageController.php:183):
public function purchase_payment_done ( $payment_data , $payment )
{
$seller = Auth :: user () -> shop ;
$seller -> seller_package_id = Session :: get ( 'payment_data' )[ 'seller_package_id' ];
$seller_package = SellerPackage :: findOrFail (
Session :: get ( 'payment_data' )[ 'seller_package_id' ]
);
$seller -> product_upload_limit = $seller_package -> product_upload_limit ;
$seller -> package_invalid_at = date ( 'Y-m-d' ,
strtotime ( $seller -> package_invalid_at . ' +' . $seller_package -> duration . 'days' )
);
$seller -> save ();
$seller_package = new SellerPackagePayment ;
$seller_package -> user_id = Auth :: user () -> id ;
$seller_package -> seller_package_id = Session :: get ( 'payment_data' )[ 'seller_package_id' ];
$seller_package -> payment_method = Session :: get ( 'payment_data' )[ 'payment_method' ];
$seller_package -> payment_details = $payment ;
$seller_package -> approval = 1 ;
$seller_package -> offline_payment = 2 ;
$seller_package -> save ();
flash ( translate ( 'Package purchasing successful' )) -> success ();
return redirect () -> route ( 'seller.dashboard' );
}
Offline Payment
Sellers can pay offline and upload receipt for verification (app/Http/Controllers/SellerPackageController.php:220):
public function purchase_package_offline ( Request $request )
{
$seller_package = SellerPackage :: findOrFail ( $request -> package_id );
// Check downgrade restriction
if ( Auth :: user () -> shop -> seller_package != null &&
$seller_package -> product_upload_limit <
Auth :: user () -> shop -> seller_package -> product_upload_limit ) {
flash ( translate ( 'You have more uploaded products than this package limit. You need to remove excessive products to downgrade.' )) -> warning ();
return redirect () -> route ( 'seller.seller_packages_list' );
}
$seller_package = new SellerPackagePayment ;
$seller_package -> user_id = Auth :: user () -> id ;
$seller_package -> seller_package_id = $request -> package_id ;
$seller_package -> payment_method = $request -> payment_option ;
$seller_package -> payment_details = $request -> trx_id ;
$seller_package -> approval = 0 ; // Pending approval
$seller_package -> offline_payment = 1 ;
$seller_package -> reciept = $request -> photo ;
$seller_package -> save ();
flash ( translate ( 'Offline payment has been done. Please wait for response.' )) -> success ();
return redirect () -> route ( 'seller.products' );
}
Offline payments require manual approval from admin before the package becomes active.
Automatic Package Expiry
Automatically unpublish products when packages expire (app/Http/Controllers/SellerPackageController.php:205):
public function unpublish_products ( Request $request )
{
foreach ( Shop :: all () as $shop ) {
if ( $shop -> package_invalid_at != null &&
Carbon :: now () -> diffInDays ( Carbon :: parse ( $shop -> package_invalid_at ), false ) <= 0 ) {
foreach ( $shop -> user -> products as $product ) {
$product -> published = 0 ;
$product -> save ();
}
$shop -> seller_package_id = null ;
$shop -> save ();
}
}
Artisan :: call ( 'cache:clear' );
}
This method should be called via a scheduled task (cron job) to automatically expire packages.
Downgrade Protection
The system prevents sellers from downgrading if they have more products than the new limit allows:
if ( Auth :: user () -> shop -> seller_package != null &&
$seller_package -> product_upload_limit <
Auth :: user () -> shop -> seller_package -> product_upload_limit ) {
flash ( translate ( 'You have more uploaded products than this package limit. You need to remove excessive products to downgrade.' )) -> warning ();
return back ();
}
Package Translations
Supports multi-language package names:
public function update ( Request $request , $id )
{
$seller_package = SellerPackage :: findOrFail ( $id );
if ( $request -> lang == env ( "DEFAULT_LANGUAGE" )) {
$seller_package -> name = $request -> name ;
}
$seller_package -> amount = $request -> amount ;
$seller_package -> product_upload_limit = $request -> product_upload_limit ;
$seller_package -> duration = $request -> duration ;
$seller_package -> logo = $request -> logo ;
if ( $seller_package -> save ()) {
$seller_package_translation = SellerPackageTranslation :: firstOrNew ([
'lang' => $request -> lang ,
'seller_package_id' => $seller_package -> id
]);
$seller_package_translation -> name = $request -> name ;
$seller_package_translation -> save ();
flash ( translate ( 'Package has been inserted successfully' )) -> success ();
return redirect () -> route ( 'seller_packages.index' );
}
}
Permissions
Package management uses role-based permissions:
public function __construct () {
$this -> middleware ([ 'permission:view_all_seller_packages' ]) -> only ( 'index' );
$this -> middleware ([ 'permission:add_seller_package' ]) -> only ( 'create' );
$this -> middleware ([ 'permission:edit_seller_package' ]) -> only ( 'edit' );
$this -> middleware ([ 'permission:delete_seller_package' ]) -> only ( 'destroy' );
}
Payment History
Sellers can view their package purchase history (app/Http/Controllers/SellerPackageController.php:148):
public function packages_payment_list ()
{
$seller_packages_payment = SellerPackagePayment :: with ( 'seller_package' )
-> where ( 'user_id' , Auth :: user () -> id )
-> paginate ( 15 );
return view ( 'seller_packages.frontend.packages_payment_list' ,
compact ( 'seller_packages_payment' ));
}
Seller Management Manage seller accounts and verification
Wholesale Products Check seller package limits when adding wholesale products