Compare commits
No commits in common. "d2c72a3f3337c9b2d384af80a8993b97025097e6" and "ea4f46f96de2f3784a0fb16df6b18d9665b5d45a" have entirely different histories.
d2c72a3f33
...
ea4f46f96d
31
.env.example
31
.env.example
@ -1,9 +1,9 @@
|
||||
APP_NAME="Top Notch"
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:vRgghlbIdXQxXIEvgUArbI9FURhgdyqx3LDXDwHYSmA=
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=localhost
|
||||
APP_URL=http://localhost
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
@ -19,12 +19,12 @@ LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=mysql
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=laravel
|
||||
DB_USERNAME=sail
|
||||
DB_PASSWORD=password
|
||||
DB_CONNECTION=sqlite
|
||||
# DB_HOST=127.0.0.1
|
||||
# DB_PORT=3306
|
||||
# DB_DATABASE=laravel
|
||||
# DB_USERNAME=root
|
||||
# DB_PASSWORD=
|
||||
|
||||
SESSION_DRIVER=database
|
||||
SESSION_LIFETIME=120
|
||||
@ -42,13 +42,13 @@ CACHE_PREFIX=
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=redis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=mailpit
|
||||
MAIL_PORT=1025
|
||||
MAIL_MAILER=log
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
@ -62,8 +62,3 @@ AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
|
||||
SCOUT_DRIVER=meilisearch
|
||||
MEILISEARCH_HOST=http://meilisearch:7700
|
||||
|
||||
MEILISEARCH_NO_ANALYTICS=false
|
||||
|
14
README.md
14
README.md
@ -1,18 +1,4 @@
|
||||
# Changelog
|
||||
**2025-04-11**
|
||||
- Fixed #132 - Inches / cm toggle for order page (and show unit on pdf)
|
||||
|
||||
**2025-04-10**
|
||||
- Fixed #145 - Default order sort is incorrect (newest will always show on top now)
|
||||
- Fixed #142 - Packing Slip content field should be required
|
||||
|
||||
**2025-04-08**
|
||||
- Added #138 - Add Decoration method to order list
|
||||
- Fixed #133 - Make product name not required
|
||||
- Fixed #127 - Implement resource lock for orders
|
||||
- Fixed #125 - 'Add Payment' on LIst Invoice page modal is too wide
|
||||
- Fixed #124 - Reorder button for product services is displayed on wrong side
|
||||
- Fixed #123 - Typo 'Add to product Services'
|
||||
|
||||
**2025-03-11**
|
||||
- Fixed #122 - Non-admins can see payments
|
||||
|
@ -2,10 +2,9 @@
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
use Filament\Support\Contracts\HasColor;
|
||||
use Filament\Support\Contracts\HasLabel;
|
||||
|
||||
enum OrderType: string implements HasColor, HasLabel
|
||||
enum OrderType: string implements HasLabel
|
||||
{
|
||||
case EMB = 'embroidery';
|
||||
case SCP = 'screen_printing';
|
||||
@ -23,15 +22,4 @@ public function getLabel(): string
|
||||
self::MISC => 'Misc',
|
||||
};
|
||||
}
|
||||
|
||||
public function getColor(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::EMB => 'embroidery',
|
||||
self::SCP => 'screen_printing',
|
||||
self::DTG => 'primary',
|
||||
self::VINYL => 'vinyl',
|
||||
self::MISC => 'misc',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -249,7 +249,6 @@ public static function table(Table $table): Table
|
||||
BulkAction::make('Create Payment')
|
||||
->icon(IconEnum::PAYMENTS->value)
|
||||
->form(fn ($form) => PaymentResource::form($form))
|
||||
->modalWidth('lg')
|
||||
->action(function (Collection $records, array $data) {
|
||||
if ($records->pluck('customer_id')->unique()->count() !== 1) {
|
||||
Notification::make()
|
||||
|
@ -33,29 +33,12 @@
|
||||
use Filament\Tables\Actions\BulkActionGroup;
|
||||
use Filament\Tables\Columns\IconColumn\IconColumnSize;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Table;
|
||||
use Guava\FilamentClusters\Forms\Cluster;
|
||||
use Icetalker\FilamentTableRepeater\Forms\Components\TableRepeater;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
function recalculateRowTotal(callable $set, callable $get): void
|
||||
{
|
||||
$amounts = collect([
|
||||
$get('xs'),
|
||||
$get('s'),
|
||||
$get('m'),
|
||||
$get('l'),
|
||||
$get('xl'),
|
||||
$get('2xl'),
|
||||
$get('3xl'),
|
||||
$get('osfa'),
|
||||
])->map(fn ($val) => floatval($val ?? 0));
|
||||
|
||||
$set('total', $amounts->sum());
|
||||
}
|
||||
|
||||
class OrderResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Order::class;
|
||||
@ -68,8 +51,6 @@ public static function form(Form $form): Form
|
||||
{
|
||||
return $form->schema([
|
||||
Group::make()
|
||||
->columns(6)
|
||||
->columnSpan(2)
|
||||
->schema([
|
||||
Section::make([
|
||||
Grid::make(1)
|
||||
@ -158,82 +139,55 @@ public static function form(Form $form): Form
|
||||
->columnSpan(1)
|
||||
->hidden(fn (?Order $record) => $record === null)
|
||||
->extraAttributes(['class' => 'h-full']),
|
||||
]),
|
||||
])
|
||||
->columns(6)
|
||||
->columnSpan(2),
|
||||
|
||||
TableRepeater::make('order_products')
|
||||
->label('Garments')
|
||||
->addActionLabel('Add new garment')
|
||||
->reorderable()
|
||||
->cloneable()
|
||||
->defaultItems(1)
|
||||
->schema([
|
||||
TextInput::make('sku')
|
||||
->datalist(OrderProduct::all()->unique('sku')->pluck('sku')->toArray()),
|
||||
TextInput::make('product_name')
|
||||
->datalist(OrderProduct::all()->unique('product_name')->pluck('product_name')->toArray()),
|
||||
->datalist(OrderProduct::all()->unique('product_name')->pluck('product_name')->toArray())
|
||||
->required(),
|
||||
TextInput::make('color')
|
||||
->datalist(OrderProduct::all()->unique('color')->pluck('color')->toArray()),
|
||||
Cluster::make([
|
||||
TextInput::make('xs')
|
||||
->placeholder('xs')
|
||||
->rules('numeric')
|
||||
->reactive()
|
||||
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||
|
||||
->rules('numeric'),
|
||||
TextInput::make('s')
|
||||
->placeholder('s')
|
||||
->rules('numeric')
|
||||
->reactive()
|
||||
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||
|
||||
->rules('numeric'),
|
||||
TextInput::make('m')
|
||||
->placeholder('m')
|
||||
->rules('numeric')
|
||||
->reactive()
|
||||
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||
|
||||
->rules('numeric'),
|
||||
TextInput::make('l')
|
||||
->placeholder('l')
|
||||
->rules('numeric')
|
||||
->reactive()
|
||||
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||
|
||||
->rules('numeric'),
|
||||
TextInput::make('xl')
|
||||
->placeholder('xl')
|
||||
->rules('numeric')
|
||||
->reactive()
|
||||
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||
|
||||
->rules('numeric'),
|
||||
TextInput::make('2xl')
|
||||
->placeholder('2xl')
|
||||
->rules('numeric')
|
||||
->reactive()
|
||||
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||
|
||||
->rules('numeric'),
|
||||
TextInput::make('3xl')
|
||||
->placeholder('3xl')
|
||||
->rules('numeric')
|
||||
->reactive()
|
||||
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||
|
||||
->rules('numeric'),
|
||||
TextInput::make('osfa')
|
||||
->placeholder('osfa')
|
||||
->rules('numeric')
|
||||
->reactive()
|
||||
->afterStateUpdated(fn ($state, callable $set, callable $get) => recalculateRowTotal($set, $get)),
|
||||
])->label('Sizes'),
|
||||
|
||||
TextInput::make('total')
|
||||
->disabled()
|
||||
->dehydrated(false)
|
||||
->afterStateHydrated(fn (callable $get, callable $set) => recalculateRowTotal($set, $get)),
|
||||
|
||||
]),
|
||||
->rules('numeric'),
|
||||
])
|
||||
->label('Sizes'),
|
||||
])
|
||||
->reorderable()
|
||||
->cloneable()
|
||||
->defaultItems(1),
|
||||
|
||||
Repeater::make('services')
|
||||
->view('filament.forms.compact-repeater')
|
||||
->label('Product Services')
|
||||
->addActionLabel('Add new product service')
|
||||
->schema([
|
||||
Grid::make(19)
|
||||
->schema([
|
||||
@ -274,44 +228,34 @@ public static function form(Form $form): Form
|
||||
->prefix('h')
|
||||
->rules('numeric'),
|
||||
])
|
||||
->label('Dimensions')
|
||||
->label('Dimensions (inches)')
|
||||
->columnSpan(4),
|
||||
|
||||
TextInput::make('amount')
|
||||
->label('Quantity')
|
||||
->live()
|
||||
->prefix('#')
|
||||
->columnSpan(2)
|
||||
->rules('numeric'),
|
||||
|
||||
TextInput::make('amount_price')
|
||||
->label('Unit price')
|
||||
->label('Amount')
|
||||
->prefix('$')
|
||||
->columnSpan(2)
|
||||
->rules('numeric'),
|
||||
]),
|
||||
|
||||
Grid::make(19)
|
||||
Grid::make(9)
|
||||
->schema([
|
||||
TextInput::make('serviceFileCode')
|
||||
->label('Code')
|
||||
->datalist(ServiceFile::all()->unique('code')->pluck('code')->toArray())
|
||||
->columnSpan(2)
|
||||
->columnSpan(1)
|
||||
->placeholder('A1234'),
|
||||
|
||||
Select::make('serviceFileSizeUnit')
|
||||
->columnSpan(2)
|
||||
->selectablePlaceholder(false)
|
||||
->label('Unit')
|
||||
->options([
|
||||
'in' => 'Inches',
|
||||
'cm' => 'cm',
|
||||
]),
|
||||
|
||||
Textarea::make('notes')
|
||||
->placeholder('Thread colors... (press enter for new line)')
|
||||
->autosize()
|
||||
->rows(1)
|
||||
->columnSpan(15),
|
||||
->placeholder('Thread colors...')
|
||||
->columnSpan(8),
|
||||
]),
|
||||
])
|
||||
->reorderable()
|
||||
@ -354,11 +298,6 @@ public static function table(Table $table): Table
|
||||
})
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('order_type')
|
||||
->badge()
|
||||
->searchable()
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('customer.company_name')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
@ -387,16 +326,8 @@ public static function table(Table $table): Table
|
||||
->searchable()
|
||||
->sortable(),
|
||||
])
|
||||
->defaultSort('id', 'desc')
|
||||
->defaultSort('order_date', 'desc')
|
||||
->filters([
|
||||
SelectFilter::make('order_type')
|
||||
->options(OrderType::class)
|
||||
->multiple(),
|
||||
|
||||
SelectFilter::make('status')
|
||||
->options(OrderStatus::class)
|
||||
->multiple(),
|
||||
|
||||
Tables\Filters\Filter::make('order_date')
|
||||
->form([
|
||||
DatePicker::make('created_from'),
|
||||
|
@ -63,7 +63,6 @@ protected function handleRecordCreation(array $data): Order
|
||||
'width' => $service['serviceFileWidth'] ?? null,
|
||||
'height' => $service['serviceFileHeight'] ?? null,
|
||||
'setup_number' => $service['serviceFileSetupNumber'] ?? null,
|
||||
'size_unit' => $service['serviceFileSizeUnit'] ?? 'inch',
|
||||
]);
|
||||
|
||||
ProductService::create([
|
||||
|
@ -21,12 +21,9 @@
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Kenepa\ResourceLock\Resources\Pages\Concerns\UsesResourceLock;
|
||||
|
||||
class EditOrder extends EditRecord
|
||||
{
|
||||
use UsesResourceLock;
|
||||
|
||||
protected static string $resource = OrderResource::class;
|
||||
|
||||
public function getTitle(): string|Htmlable
|
||||
@ -68,7 +65,6 @@ protected function mutateFormDataBeforeFill(array $data): array
|
||||
'serviceFileHeight' => $service->serviceFile->height ?? '',
|
||||
'serviceFileCode' => $service->serviceFile->code ?? '',
|
||||
'serviceFileSetupNumber' => $service->serviceFile->setup_number ?? '',
|
||||
'serviceFileSizeUnit' => $service->serviceFile->size_unit ?? 'inch',
|
||||
];
|
||||
}
|
||||
|
||||
@ -140,7 +136,6 @@ public function handleRecordUpdate(Model $record, array $data): Model
|
||||
'width' => $service['serviceFileWidth'] ?? null,
|
||||
'height' => $service['serviceFileHeight'] ?? null,
|
||||
'setup_number' => $service['serviceFileSetupNumber'] ?? null,
|
||||
'size_unit' => $service['serviceFileSizeUnit'] ?? 'inch',
|
||||
]);
|
||||
|
||||
ProductService::create([
|
||||
|
@ -10,17 +10,11 @@
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Components\Tab;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
use Filament\Support\Enums\MaxWidth;
|
||||
|
||||
class ListOrders extends ListRecords
|
||||
{
|
||||
protected static string $resource = OrderResource::class;
|
||||
|
||||
public function getMaxContentWidth(): string
|
||||
{
|
||||
return 'max-w-[1920px]';
|
||||
}
|
||||
|
||||
private function excludeStatuses($query): mixed
|
||||
{
|
||||
return $query
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Filament\Admin\Resources;
|
||||
|
||||
use App\Enums\IconEnum;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Order;
|
||||
use App\Models\PackingSlip;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
@ -38,16 +39,11 @@ public static function form(Form $form): Form
|
||||
DatePicker::make('date_received')
|
||||
->default(today())
|
||||
->required(),
|
||||
|
||||
Select::make('customer_id')
|
||||
->label('Customer')
|
||||
->relationship(name: 'customer', titleAttribute: 'company_name')
|
||||
->preload()
|
||||
->createOptionForm(fn ($form) => CustomerResource::form($form))
|
||||
->createOptionAction(fn ($action) => $action->modalWidth('lg'))
|
||||
->options(Customer::all()->pluck('company_name', 'id'))
|
||||
->reactive()
|
||||
->searchable(),
|
||||
|
||||
Select::make('order_id')
|
||||
->label('Order')
|
||||
->options(fn ($get): array => Order::where('customer_id', $get('customer_id') ?? null)
|
||||
@ -61,7 +57,6 @@ public static function form(Form $form): Form
|
||||
Grid::make(1)
|
||||
->schema([
|
||||
TextArea::make('contents')
|
||||
->required()
|
||||
->rows(9),
|
||||
])
|
||||
->columnSpan(1),
|
||||
@ -78,6 +73,7 @@ public static function table(Table $table): Table
|
||||
->sortable()
|
||||
->searchable(),
|
||||
TextColumn::make('order.customer_po')
|
||||
// ->url(fn ($record) => $record->to)
|
||||
->url(fn ($record) => OrderResource::getUrl('edit', ['record' => $record->id]))
|
||||
->weight('bold')
|
||||
->color('code')
|
||||
|
@ -49,7 +49,7 @@ private function getOrdersPast30Days(): string
|
||||
->where('order_status', '!=', OrderStatus::READY_FOR_INVOICE)
|
||||
->where('order_status', '!=', OrderStatus::SHIPPED)
|
||||
->where('order_status', '!=', OrderStatus::INVOICED)
|
||||
->whereBetween('created_at', [now()->subDays(30), now()])
|
||||
->whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])
|
||||
->count();
|
||||
}
|
||||
|
||||
|
@ -16,14 +16,13 @@
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Kenepa\ResourceLock\Models\Concerns\HasLocks;
|
||||
|
||||
#[ObservedBy(OrderObserver::class)]
|
||||
|
||||
class Order extends Model
|
||||
{
|
||||
/** @use HasFactory<OrderFactory> */
|
||||
use HasFactory, HasLocks, SoftDeletes;
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'customer_id',
|
||||
|
@ -26,7 +26,6 @@ class ProductService extends Model
|
||||
'amount',
|
||||
'amount_price',
|
||||
'notes',
|
||||
'size_unit',
|
||||
];
|
||||
|
||||
protected $appends = [
|
||||
|
@ -19,7 +19,6 @@ class ServiceFile extends Model
|
||||
'width',
|
||||
'height',
|
||||
'setup_number',
|
||||
'size_unit',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -18,7 +18,6 @@
|
||||
use Illuminate\Session\Middleware\AuthenticateSession;
|
||||
use Illuminate\Session\Middleware\StartSession;
|
||||
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||
use Kenepa\ResourceLock\ResourceLockPlugin;
|
||||
|
||||
class AdminPanelProvider extends PanelProvider
|
||||
{
|
||||
@ -30,14 +29,10 @@ public function panel(Panel $panel): Panel
|
||||
->path('admin')
|
||||
->login(UsernameLogin::class)
|
||||
->colors([
|
||||
'primary' => Color::Blue,
|
||||
'code' => Color::hex('#d63384'),
|
||||
'invoicing' => Color::hex('#DD00DD'),
|
||||
'invoiced' => Color::hex('#900090'),
|
||||
'embroidery' => Color::hex('#FF00FF'),
|
||||
'screen_printing' => Color::hex('#0088FF'),
|
||||
'vinyl' => Color::hex('#22AA22'),
|
||||
'misc' => Color::hex('#0000FF'),
|
||||
'primary' => Color::Blue,
|
||||
'code' => Color::hex('#d63384'),
|
||||
'invoicing' => Color::hex('#DD00DD'),
|
||||
'invoiced' => Color::hex('#900090'),
|
||||
])
|
||||
->discoverResources(in: app_path('Filament/Admin/Resources/'), for: 'App\\Filament\\Admin\\Resources')
|
||||
->discoverPages(in: app_path('Filament/Admin/Pages'), for: 'App\\Filament\\Admin\\Pages')
|
||||
@ -67,7 +62,6 @@ public function panel(Panel $panel): Panel
|
||||
NavigationGroup::make('Financial'),
|
||||
NavigationGroup::make('Reports'),
|
||||
NavigationGroup::make('Settings'),
|
||||
])
|
||||
->plugin(ResourceLockPlugin::make());
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -7,17 +7,15 @@
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"davidhsianturi/blade-bootstrap-icons": "^1.5",
|
||||
"doctrine/dbal": "^4.2",
|
||||
"fakerphp/faker": "^1.23",
|
||||
"filament/filament": "^3.2",
|
||||
"guava/filament-clusters": "^1.4",
|
||||
"icetalker/filament-table-repeater": "^1.3",
|
||||
"kenepa/resource-lock": "^2.1",
|
||||
"laravel/framework": "^11.9",
|
||||
"laravel/tinker": "^2.9",
|
||||
"livewire/livewire": "^3.5",
|
||||
"mallardduck/blade-lucide-icons": "^1.23",
|
||||
"spatie/laravel-pdf": "^1.5"
|
||||
"spatie/laravel-pdf": "^1.5",
|
||||
"fakerphp/faker": "^1.23"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-ide-helper": "^3.5",
|
||||
|
70
composer.lock
generated
70
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "139b4d2b0a40ace1cf1efaf4c7facf20",
|
||||
"content-hash": "46ac06345fc3d57a7d0a01cfcaeaac17",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anourvalar/eloquent-serialize",
|
||||
@ -2238,74 +2238,6 @@
|
||||
],
|
||||
"time": "2025-03-05T16:06:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "kenepa/resource-lock",
|
||||
"version": "2.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/kenepa/resource-lock.git",
|
||||
"reference": "dda6e14b5c4a47817569081b11248c572ebdfd07"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/kenepa/resource-lock/zipball/dda6e14b5c4a47817569081b11248c572ebdfd07",
|
||||
"reference": "dda6e14b5c4a47817569081b11248c572ebdfd07",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"filament/filament": "^3.0",
|
||||
"illuminate/contracts": "^9.0|^10.0|^11.0|^12.0",
|
||||
"php": "^8.1",
|
||||
"spatie/laravel-package-tools": "^1.15.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "^1.0",
|
||||
"nunomaduro/collision": "^7.0|^8.1",
|
||||
"nunomaduro/larastan": "^2.0.1",
|
||||
"orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
|
||||
"pestphp/pest": "^2.0|^3.7",
|
||||
"pestphp/pest-plugin-laravel": "^2.0|^3.1",
|
||||
"pestphp/pest-plugin-livewire": "^2.0|^3.0",
|
||||
"phpstan/extension-installer": "^1.1",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.0|^2.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0|^2.0",
|
||||
"spatie/laravel-ray": "^1.26",
|
||||
"tightenco/duster": "^1.1|^3.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"ResourceLock": "Kenepa\\ResourceLock\\Facades\\ResourceLock"
|
||||
},
|
||||
"providers": [
|
||||
"Kenepa\\ResourceLock\\ResourceLockServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Kenepa\\ResourceLock\\": "src",
|
||||
"Kenepa\\ResourceLock\\Database\\Factories\\": "database/factories"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Filament Resource Lock is a Filament plugin that adds resource locking functionality to your site.",
|
||||
"homepage": "https://github.com/kenepa/resource-lock",
|
||||
"keywords": [
|
||||
"Kenepa",
|
||||
"laravel",
|
||||
"resource-lock"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/kenepa/resource-lock/issues",
|
||||
"source": "https://github.com/kenepa/resource-lock/tree/2.1.3"
|
||||
},
|
||||
"time": "2025-03-14T16:31:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "kirschbaum-development/eloquent-power-joins",
|
||||
"version": "4.2.1",
|
||||
|
@ -25,7 +25,7 @@
|
||||
| or any other location as required by the application or its packages.
|
||||
*/
|
||||
|
||||
'version' => '20250411',
|
||||
'version' => '20250311',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -1,130 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Models
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The models configuration specifies the classes that represent your application's
|
||||
| data objects. This configuration is used by the framework to interact with
|
||||
| the application's data models. You can even implement your own ResourceLock model.
|
||||
|
|
||||
*/
|
||||
|
||||
'models' => [
|
||||
'User' => \App\Models\User::class,
|
||||
// 'ResourceLock' => null,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Filament Resource
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The resource lock filament resource displays all the current locks in place.
|
||||
| You are able to replace the resource Lock with your own resource class.
|
||||
|
|
||||
*/
|
||||
'resource' => [
|
||||
'class' => \Kenepa\ResourceLock\Resources\LockResource::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Resource Unlocker Button
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The unlocker configuration specifies whether limited access is enabled for
|
||||
| the resource unlock button. If limited access is enabled, only specific
|
||||
| users or roles will be able to unlock locked resources directly from
|
||||
| the modal.
|
||||
|
|
||||
*/
|
||||
|
||||
'unlocker' => [
|
||||
'limited_access' => false,
|
||||
// 'gate' => ''
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Lock Notice
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The lock notice contains several configuration options for the modal
|
||||
| that is display when a resource is locked.
|
||||
|
|
||||
*/
|
||||
|
||||
'lock_notice' => [
|
||||
'display_resource_lock_owner' => false,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Resource Lock Manager
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The resource lock manager provides a simple way to view all resource locks
|
||||
| of your application. It provides several ways to quickly unlock all or
|
||||
| specific resources within your app.
|
||||
|
|
||||
*/
|
||||
|
||||
'manager' => [
|
||||
'navigation_badge' => false,
|
||||
'navigation_icon' => 'heroicon-o-lock-closed',
|
||||
'navigation_label' => 'Resource Locks',
|
||||
'plural_label' => 'Resource Locks',
|
||||
'navigation_group' => 'Settings',
|
||||
'navigation_sort' => 200,
|
||||
'limited_access' => false,
|
||||
'should_register_navigation' => true,
|
||||
// 'gate' => ''
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Lock timeout (in minutes)
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The lock_timeout configuration specifies the time interval, in minutes,
|
||||
| after which a lock on a resource will expire if it has not been manually
|
||||
| unlocked or released by the user.
|
||||
|
|
||||
*/
|
||||
|
||||
'lock_timeout' => 10,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Check Locks before saving
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The check_locks_before_saving configuration specifies whether a lock of a resource will be checked
|
||||
| before saving a resource if a tech-savvy user is able to bypass the locked
|
||||
| resource modal and attempt to save the resource. In some cases you may want to turns this off.
|
||||
| It's recommended to keep this on.
|
||||
|
|
||||
*/
|
||||
|
||||
'check_locks_before_saving' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Actions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Action classes are simple classes that execute some logic within the package.
|
||||
| If you want to add your own custom logic you are able to extend your own
|
||||
| class with class your overwriting.
|
||||
| Learn more about action classes: https://freek.dev/2442-strategies-for-making-laravel-packages-customizable
|
||||
|
|
||||
*/
|
||||
|
||||
'actions' => [
|
||||
'get_resource_lock_owner_action' => \Kenepa\ResourceLock\Actions\GetResourceLockOwnerAction::class,
|
||||
],
|
||||
];
|
@ -19,6 +19,7 @@ public function definition(): array
|
||||
'name' => $this->faker->word(),
|
||||
'width' => round($this->faker->randomFloat(2, 0, 10), 1),
|
||||
'height' => round($this->faker->randomFloat(2, 0, 10), 1),
|
||||
'unit' => 'inch',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('resource_locks', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->timestamps();
|
||||
$table->foreignId('user_id')->constrained();
|
||||
$table->morphs('lockable');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('resource_locks');
|
||||
}
|
||||
};
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('order_products', function (Blueprint $table) {
|
||||
$table->string('product_name')->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('order_products', function (Blueprint $table) {
|
||||
$table->string('product_name')->nullable(false)->change();
|
||||
});
|
||||
}
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
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::table('service_files', function (Blueprint $table) {
|
||||
$table->string('size_unit')->default('in');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('service_files', function (Blueprint $table) {
|
||||
$table->dropColumn('size_unit');
|
||||
});
|
||||
}
|
||||
};
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "order_system",
|
||||
"name": "topnotch_website",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
|
@ -118,7 +118,6 @@ class="fi-fo-repeater-item divide-y divide-gray-100 rounded-xl bg-white shadow-
|
||||
>
|
||||
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible)
|
||||
<ul class="flex items-center gap-x-3">
|
||||
{{--
|
||||
@if ($reorderActionIsVisible)
|
||||
<li
|
||||
x-sortable-handle
|
||||
@ -127,7 +126,6 @@ class="fi-fo-repeater-item divide-y divide-gray-100 rounded-xl bg-white shadow-
|
||||
{{ $reorderAction }}
|
||||
</li>
|
||||
@endif
|
||||
--}}
|
||||
|
||||
@if ($moveUpActionIsVisible || $moveDownActionIsVisible)
|
||||
<li
|
||||
@ -158,7 +156,7 @@ class="flex items-center justify-center"
|
||||
</h4>
|
||||
@endif
|
||||
|
||||
@if ($cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions || $reorderActionIsVisible)
|
||||
@if ($cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions)
|
||||
<ul
|
||||
class="ms-auto flex items-center gap-x-3"
|
||||
>
|
||||
@ -168,15 +166,6 @@ class="ms-auto flex items-center gap-x-3"
|
||||
</li>
|
||||
@endforeach
|
||||
|
||||
@if ($reorderActionIsVisible)
|
||||
<li
|
||||
x-sortable-handle
|
||||
x-on:click.stop
|
||||
>
|
||||
{{ $reorderAction }}
|
||||
</li>
|
||||
@endif
|
||||
|
||||
@if ($cloneActionIsVisible)
|
||||
<li x-on:click.stop>
|
||||
{{ $cloneAction }}
|
||||
|
@ -111,9 +111,7 @@
|
||||
</div>
|
||||
<div class="fs-6 text-primary">
|
||||
{{$order->customer_po}}
|
||||
@if($order->pre_production)
|
||||
<span class="text-danger"> (pre-pro)</span>
|
||||
@endif()
|
||||
@if($order->pre_production)<span class="text-danger"> (pre-pro)</span>@endif()
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -155,7 +153,7 @@
|
||||
<tbody>
|
||||
@foreach($order->orderProducts as $product)
|
||||
<tr>
|
||||
<td><code style="font-size: 0.9rem;">{{$product->sku}}</code></td>
|
||||
<td><code>{{$product->sku}}</code></td>
|
||||
<td class="text-uppercase">{{$product->product_name}}</td>
|
||||
<td class="text-uppercase">{{$product->color}}</td>
|
||||
<td style="width: 40px;">{{$product->productSizes()->get()->where('size', 'xs')->first()->amount ?? ''}}</td>
|
||||
@ -184,13 +182,12 @@
|
||||
|
||||
<!-- Services Table -->
|
||||
<div class="row mt-2">
|
||||
<table class="table table-striped" style="font-size: 13px;">
|
||||
<table class="table table-striped" style="font-size: 12px;">
|
||||
<thead class="opacity-50 fw-normal">
|
||||
<th>Placement & Service</th>
|
||||
<th class="w-50">Logo Name & Instructions</th>
|
||||
<th>Width</th>
|
||||
<th>Height</th>
|
||||
<th>Unit</th>
|
||||
<th>QTY</th>
|
||||
</thead>
|
||||
|
||||
@ -203,18 +200,18 @@
|
||||
</div>
|
||||
<br>
|
||||
<div class="text-uppercase">
|
||||
<code style="font-size: 14px">
|
||||
{{$service->serviceFile->code ?? ''}}
|
||||
<code style="font-size: 12px">
|
||||
{{$service->serviceFile->code}}
|
||||
</code>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="text-uppercase">
|
||||
{{$service->serviceFile->name ?? ''}}
|
||||
{{$service->serviceFile->name}}
|
||||
</div>
|
||||
<br>
|
||||
<div class="text-uppercase" style="color: #d63384;">
|
||||
{{$service->notes ?? ''}}
|
||||
<div class="text-uppercase">
|
||||
{{$service->notes}}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
@ -223,9 +220,6 @@
|
||||
<td>
|
||||
{{$service->serviceFile->height}}
|
||||
</td>
|
||||
<td>
|
||||
{{$service->serviceFile->size_unit}}
|
||||
</td>
|
||||
<td>
|
||||
{{$service->amount}}
|
||||
</td>
|
||||
|
@ -6,11 +6,9 @@ export default {
|
||||
"./app/Filament/**/*.php",
|
||||
"./vendor/filament/**/*.php"
|
||||
],
|
||||
safelist: [
|
||||
'max-w-[1920px]'
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@
|
||||
->assertHasNoErrors();
|
||||
|
||||
$this->assertDatabaseHas('invoices', [
|
||||
'internal_id' => 'TN4001',
|
||||
'internal_id' => 'TN40001',
|
||||
'customer_id' => $formData['customer_id'],
|
||||
'status' => $formData['status'],
|
||||
'has_gst' => $formData['has_gst'],
|
||||
@ -65,7 +65,7 @@
|
||||
'hst_rate' => $hst_rate,
|
||||
]);
|
||||
|
||||
$invoice = Invoice::where('internal_id', 'TN4001')->firstOrFail();
|
||||
$invoice = Invoice::where('internal_id', 'TN40001')->firstOrFail();
|
||||
|
||||
$this->assertEquals($invoice->orders->isEmpty(), true);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user