Absolutely, you can add selling "sets" (or bundles) functionality to your current Laravel database structure. Below is an approach to extend your design so you can sell both individual items and sets of items.
1. Database Design: Introducing Sets
Add a new table, item_sets, to represent a "Set" (like AYZ), and an item_set_components table to define which items (and quantities) are included.
Migration Example
php artisan make:model ItemSet -m
php artisan make:model ItemSetComponent -m
item_sets Table
// database/migrations/xxxx_xx_xx_create_item_sets_table.php
Schema::create('item_sets', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->decimal('price', 12, 2); // Total price for the entire set
$table->timestamps();
});
item_set_components Table
// database/migrations/xxxx_xx_xx_create_item_set_components_table.php
Schema::create('item_set_components', function (Blueprint $table) {
$table->id();
$table->foreignId('item_set_id')->constrained()->onDelete('cascade');
$table->foreignId('inventory_item_id')->constrained()->onDelete('cascade');
$table->integer('quantity'); // Amount of this InventoryItem in the set
$table->timestamps();
});
2. Eloquent Models
Define relationships:
ItemSet Model
class ItemSet extends Model
{
protected $fillable = ['name', 'price'];
public function components()
{
return $this->hasMany(ItemSetComponent::class);
}
}
ItemSetComponent Model
class ItemSetComponent extends Model
{
protected $fillable = ['item_set_id', 'inventory_item_id', 'quantity'];
public function inventoryItem()
{
return $this->belongsTo(InventoryItem::class);
}
public function itemSet()
{
return $this->belongsTo(ItemSet::class);
}
}
3. Selling a Set: Storing in SoldInventoryItems
Option 1: Store set sale in a different SoldInventoryItem row, using a nullable item_set_id.
Alter SoldInventoryItems:
- Add
item_set_id(nullable):
$table->foreignId('item_set_id')->nullable()->constrained()->onDelete('set null');
Then when selling a set (say, 2 x AYZ):
- Create a SoldInventoryItems row representing 2 sets, with the
item_set_idfield set. - For inventory management and reporting, also decrease the quantities of all included InventoryItems by the correct multiple.
Or, when a set is sold, for updating stock and for clarity:
- For each InventoryItem in the set, create a SoldInventoryItems row for the individual item, totaling the quantity (
component quantityxset quantity), and indicate with a field (e.g.,is_part_of_set,item_set_id).
4. Implementation in Your Sale Workflow
When selling a set (e.g. AYZ 2 sets):
Find the set definition:
$set = ItemSet::with('components.inventoryItem')->where('name', 'AYZ')->first();
$setQty = 2;
$setPrice = $set->price;
For each component:
foreach ($set->components as $component) {
$quantityToSell = $component->quantity * $setQty;
// Create SoldInventoryItems for each component
SoldInventoryItems::create([
'inventory_in_store_id' => $component->inventoryItem->inventoryInStores()->where('store_id', $storeId)->first()->id,
'quantity' => $quantityToSell,
'unit_price' => 0, // You may leave unit price as 0, or allocate proportionally if you wish
'sub_total' => 0,
'item_set_id' => $set->id, // So you know it was sold as part of a set
]);
// Reduce stock in InventoryInStore accordingly
}
And create another SoldInventoryItems row for the set itself (optional for reporting):
SoldInventoryItems::create([
// 'inventory_in_store_id' => null or optional,
'quantity' => $setQty,
'unit_price' => $set->price,
'sub_total' => $set->price * $setQty,
'item_set_id' => $set->id,
]);
You can adjust your Livewire component logic to allow the operator to choose between "individual" or "set" at sale time.
5. Display
When viewing a sale, you show:
- If
item_set_idis present, display it clearly as a set (with breakdown of its items). - Or group SoldInventoryItems by
item_set_idto show sets.
Summary
- Add
item_setsanditem_set_componentsfor flexible set (bundle) support. - Update your sale flow to allow selecting/selling sets, and store all necessary rows for transparency and reporting.
- Adjust inventory levels for individual items inside the sold sets.
This approach is scalable, reversible, and doesn't break your current single-item logic.
If you want code for a specific controller/store action or Livewire logic, just ask!