pictastudio / venditio
ecommerce package
Fund package maintenance!
Picta Studio
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 2
Forks: 0
Open Issues: 4
pkg:composer/pictastudio/venditio
Requires
- php: ^8.4
- illuminate/contracts: ^12.8
- nevadskiy/laravel-tree: ^0.6.1
- spatie/laravel-activitylog: ^4.7
- spatie/laravel-package-tools: ^1.16
- spatie/laravel-permission: ^6.3
- spatie/laravel-sluggable: ^3.7
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.0
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^10.4
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/phpstan: ^2.0
- dev-main
- 1.x-dev
- v1.0.0
- 0.x-dev
- v0.1.9
- v0.1.8
- v0.1.7
- v0.1.6
- v0.1.5
- v0.1.4
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1.0
- dev-rename-to-venditio
- dev-multiple-price-lists
- dev-arch-update
- dev-dependabot/github_actions/dependabot/fetch-metadata-2.5.0
- dev-dependabot/github_actions/actions/checkout-6
- dev-dependabot/github_actions/stefanzweifel/git-auto-commit-action-7
- dev-dependabot/composer/spatie/laravel-query-builder-tw-6.3
This package is auto-updated.
Last update: 2026-02-12 16:27:58 UTC
README
Venditio it's a headless e-commerce tool. It provides the functionality for an e-commerce laravel based application, giving you the freedom to choose the frontend stack.
We offer Venditio admin a complementary package that provides an admin panel written with filamentphp
Installation
You can install the package via composer:
composer require pictastudio/venditio
Product Variants
Venditio models product variants by treating a base Product as the parent and variant products as the purchasable items.
This allows you to represent multiple option combinations while keeping a single product identity.
We have a t-shirt Product with id 1 that could have variants in both color and size
Considering these variants:
| size | color |
|---|---|
| S | black |
| M | white |
| L | red |
All the variants are computed using product_variants and product_variant_options. Each concrete variant is stored as a products row with a parent_id that points to the base product. The variant row is the purchasable item and is the one that should be assigned a unique sku.
| product_id | size | color |
|---|---|---|
| 1 | S | black |
| 1 | M | black |
| 1 | L | black |
| 1 | S | white |
| 1 | M | white |
| 1 | L | white |
| 1 | S | red |
| 1 | M | red |
| 1 | L | red |
Usage
Documentation
- Architecture and package design:
docs/ARCHITECTURE.md - API reference and examples:
docs/API.md
Configuration
No edition or mode selection is required. All behavior is configured via the venditio config file.
Seeding Data
Add the following seeders to your DatabaseSeeder to seed the initial data used by the package, this will seed the countries data as well as a root user, then it will create all the roles and permissions based on the auth section of the config
namespace Database\Seeders; // use Illuminate\Database\Console\Seeds\WithoutModelEvents; use Illuminate\Database\Seeder; use PictaStudio\Venditio\Database\Seeders\CountrySeeder; use PictaStudio\Venditio\Database\Seeders\CurrencySeeder; use PictaStudio\Venditio\Database\Seeders\RoleSeeder; use PictaStudio\Venditio\Database\Seeders\TaxClassSeeder; use PictaStudio\Venditio\Database\Seeders\UserSeeder; class DatabaseSeeder extends Seeder { public function run(): void { $this->call([ CountrySeeder::class, CurrencySeeder::class, TaxClassSeeder::class, RoleSeeder::class, UserSeeder::class, ]); } }
Auth
Add the HasApiTokens trait to your user model if not already present and then update the model in the config so the package can use the correct one
Also extend the User model from Venditio
namespace App\Models; use Laravel\Sanctum\HasApiTokens; use PictaStudio\Venditio\Models\User as VenditioUser; class User extends VenditioUser { use HasApiTokens; }
then update the class in config/venditio
'models' => [ // ... 'user' => App\Models\User::class, ],
If you want the package to create a root user then provide inside the .env file the following variables
VENDITIO_ROOT_USER_EMAIL=mail_here VENDITIO_ROOT_USER_PASSWORD=password_here
/* |-------------------------------------------------------------------------- | Auth |-------------------------------------------------------------------------- | | Specify the auth manager, roles, resources, actions, and extra permissions | */ 'auth' => [ // 'manager' => AuthManager::class, 'roles' => [ 'root' => Managers\AuthManager::ROLE_ROOT, 'admin' => Managers\AuthManager::ROLE_ADMIN, 'user' => Managers\AuthManager::ROLE_USER, ], 'resources' => [ 'user', 'role', 'address', 'cart', 'order', 'product', 'product-category', 'brand', ], 'actions' => [ 'view-any', 'view', 'create', 'update', 'delete', 'restore', 'force-delete', ], 'extra_permissions' => [ // 'orders' => [ // 'export', // 'export-bulk', // ], ], 'root_user' => [ 'email' => env('VENDITIO_ROOT_USER_EMAIL'), 'password' => env('VENDITIO_ROOT_USER_PASSWORD'), ], ],
Models
Inside the config you will find a section dedicated to models configuration
/* |-------------------------------------------------------------------------- | Models |-------------------------------------------------------------------------- | | Specify the models to use | */ 'models' => [ 'address' => Simple\Models\Address::class, 'brand' => Simple\Models\Brand::class, 'cart' => Simple\Models\Cart::class, 'cart_line' => Simple\Models\CartLine::class, 'country' => Simple\Models\Country::class, 'country_tax_class' => Simple\Models\CountryTaxClass::class, 'currency' => Simple\Models\Currency::class, 'discount' => Simple\Models\Discount::class, 'inventory' => Simple\Models\Inventory::class, 'order' => Simple\Models\Order::class, 'order_line' => Simple\Models\OrderLine::class, 'product' => Simple\Models\Product::class, 'product_category' => Simple\Models\ProductCategory::class, 'shipping_status' => Simple\Models\ShippingStatus::class, 'tax_class' => Simple\Models\TaxClass::class, 'user' => Simple\Models\User::class, 'product_custom_field' => Advanced\Models\ProductCustomField::class, 'product_type' => Advanced\Models\ProductType::class, 'product_variant' => Advanced\Models\ProductVariant::class, 'product_variant_option' => Advanced\Models\ProductVariantOption::class, ],
Relations
Relations inside models are defined dynamically by resolving the configured model class from the config.
// brand relation from Simple\Models\Product model public function brand(): BelongsTo { return $this->belongsTo(resolve_model('brand')); }
Validation rules
Validation rules are managed inside separate classes than FormRequests
namespace PictaStudio\Venditio\Validations; use Illuminate\Validation\Rule; use PictaStudio\Venditio\Validations\Contracts\AddressValidationRules; class AddressValidation implements AddressValidationRules { public function getStoreValidationRules(): array { return [ 'type' => [ 'required', 'string', Rule::enum(config('venditio.addresses.type_enum')), ], 'is_default' => 'sometimes|boolean', 'first_name' => 'required|string|max:255', 'last_name' => 'required|string|max:255', 'email' => 'required|email|max:255', // ... ]; } public function getUpdateValidationRules(): array { return [ 'type' => [ 'sometimes', 'string', Rule::enum(config('venditio.addresses.type_enum')), ], 'is_default' => 'sometimes|boolean', 'first_name' => 'sometimes|string|max:255', 'last_name' => 'sometimes|string|max:255', 'email' => 'sometimes|email|max:255', // ... ]; } }
this classes are then resolved out of the container when needed
namespace PictaStudio\Venditio\Http\Requests\V1\Address; use Illuminate\Foundation\Http\FormRequest; use PictaStudio\Venditio\Validations\Contracts\AddressValidationRules; class StoreAddressRequest extends FormRequest { public function authorize(): bool { return $this->user()->can('address:create'); } public function rules(AddressValidationRules $addressValidationRules): array { return $addressValidationRules->getStoreValidationRules(); } }
Customize validation rules by modifying the class bind in laravel container
use PictaStudio\Venditio\Validations\Contracts\AddressValidationRules; use App\Validations\AddressValidation; // inside AppServiceProvider boot method public function boot(): void { $this->app->singleton(AddressValidationRules::class, AddressValidation::class); }
Dto
The package uses Dtos inside the pipelines and you can modify the class it uses inside the the config file The important thing is that those classes need to implement the provided interfaces
for Order dto: PictaStudio\Venditio\Dto\Contracts\OrderDtoContract for Cart dto: PictaStudio\Venditio\Dto\Contracts\CartDtoContract
Helper functions
Utility functions used across the package to simplify resolving the correct namespaced classes
function auth_manager(User|Authenticatable|null $user = null): AuthManagerContract { return app(AuthManagerContract::class, ['user' => $user]); } /** * @param string $model String that identifies the model (one of the keys from config('venditio.models')) */ function resolve_model(string $model): string { return config('venditio.models.' . $model); } function query(string $model): Builder { return resolve_model($model)::query(); } function get_fresh_model_instance(string $model): Model { return new (resolve_model($model)); }
Api
Routes
Routes are registered once, without runtime branching
Route::apiResource('products', ProductController::class)->only(['index', 'show']);
Controllers
Controllers live directly under Http\Controllers\Api and do not switch at runtime.
Http Resources
Example of an http resource, with the array key (product.images) we are telling which attribute we want to mutate and then the closure accepts as a parameter the value of that attribute
You can use dot notation to access attributes because under the hood it uses Arr::get and Arr::set methods
protected function transformAttributes(): array { return [ 'product.images' => fn (?array $images) => ( collect($images) ->map(fn (array $image) => [ 'alt' => $image['alt'], 'img' => asset('storage/' . $image['img']), ]) ->toArray() ), 'product.files' => fn (?array $files) => ( collect($files) ->map(fn (array $file) => [ 'name' => $file['name'], 'file' => asset('storage/' . $file['file']), ]) ->toArray() ), ]; }
Cart
Generator
Customize cart identifier generator by modifying the binding in laravel container
$this->app->singleton(CartIdentifierGeneratorInterface::class, CartIdentifierGenerator::class);
Order
Generator
Customize order identifier generator by modifying the binding in laravel container
$this->app->singleton(OrderIdentifierGeneratorInterface::class, OrderIdentifierGenerator::class);
Example of custom generator class
namespace App\Generators; use PictaStudio\Venditio\Models\Order; use PictaStudio\Venditio\Orders\Contracts\OrderIdentifierGeneratorInterface; class OrderIdentifierGenerator implements OrderIdentifierGeneratorInterface { public function generate(Order $order): string { // implement your custom logic here } }
Commands
the package provides some console commands to deal with common use cases
Carts
- ReleaseStockForAbandonedCarts
checks all carts with a pending status which by default are
processingandactivepending statuses are customizable by changing thegetPendingStatuses()function inCartStatusenum which is located in the config file undercarts.status_enum
Bruno API Collection
- PublishBrunoCollection
publishes the Bruno request collection into the host app at
bruno/venditio
php artisan vendor:publish --tag=venditio-bruno
Structure
// folder structure (high level)
src/
|--- Actions
|--- Contracts
|--- Helpers
|--- Http
|--- Packages
|--- Simple // models, enums, validations, factories (internal module)
|--- Advanced // variant system models, validations, factories (internal module)
TODO:
- update outdated docs
- docs on global available helpers
- pipelines docs
- docs on
OrderStatusenum andContracts\OrderStatuson how it's used and the logic behind it - fix updating cart lines in
CartUpdatePipeline(add line/s and recalculate cart totals)
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.