Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
424446d
upgraded dependencies
roncodes Jul 19, 2024
73033b6
upgraded core dependencies
roncodes Oct 2, 2024
b343c62
fix transitions
roncodes Dec 23, 2024
7d190cd
feat: Enterprise WMS refactoring with Fleetops architecture
Nov 7, 2025
12dcd40
feat: Complete component refactoring for all resources
Nov 15, 2025
6d28748
Merge pull request #5 from fleetbase/feature/enterprise-wms-refactor
roncodes Feb 28, 2026
bd5b356
feat: Milestone 1 - Critical bug fixes (backend + frontend)
roncodes Feb 28, 2026
4e09d9b
Fix extension structure
roncodes Feb 28, 2026
cc33782
Merge branch 'dev-v0.0.2' of github.com:fleetbase/pallet into dev-v0.0.2
roncodes Feb 28, 2026
e9572c5
feat: Milestone 3 - Audit model refactor as WMS operational audit trail
roncodes Feb 28, 2026
bfde811
feat: Milestone 4 - PO/SO Line Items (backend + frontend)
roncodes Feb 28, 2026
f6f3d46
feat: Milestone 5 - Receive PO and Fulfill SO workflows
roncodes Feb 28, 2026
ab3d8b8
fix: correct mismatched {{#if}}/{{#each}} blocks in PO and SO items t…
roncodes Feb 28, 2026
be270ab
fix template and upgraded dependencies
roncodes Mar 1, 2026
03582c7
Merge branch 'dev-v0.0.2' of github.com:fleetbase/pallet into dev-v0.0.2
roncodes Mar 1, 2026
ad097b4
feat: Milestone 6 - Dashboard with Widget system integration
roncodes Mar 1, 2026
d4ce2e1
fix: Convert all named-class migrations to anonymous class pattern
roncodes Mar 1, 2026
c364213
fix: Correct foreign key references in order items migration
roncodes Mar 1, 2026
663c579
fix: Correct inventory foreign key table name in order items migration
roncodes Mar 1, 2026
485be88
refactor(warehouse): promote Warehouse to first-class model with pall…
Mar 2, 2026
5a4d339
Upgraded core dependencies
roncodes Apr 24, 2026
ded4a73
latest
roncodes Jun 4, 2026
155374a
dashboard refactor
roncodes Jun 12, 2026
e71051c
upgraded dependencies
roncodes Jun 12, 2026
55247cf
latest
roncodes Jun 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
50 changes: 27 additions & 23 deletions .github/workflows/ember.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,33 @@ on:
pull_request:
branches: [ main ]

env:
NODE_VERSION: 22.x

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x] # Build on Node.js 18

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: ${{ env.NODE_VERSION }}

- name: Setup pnpm
uses: pnpm/action-setup@v2.0.1
uses: pnpm/action-setup@v4
with:
version: latest

- name: Install Dependencies
run: pnpm install
run: pnpm install --frozen-lockfile

- name: Lint
run: pnpm run lint

- name: Test
run: pnpm run test:ember

- name: Build
run: pnpm run build
Expand All @@ -40,20 +44,20 @@ jobs:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Setup Node.js 18.x
uses: actions/setup-node@v2
- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: 18.x
node-version: ${{ env.NODE_VERSION }}

- name: Setup pnpm
uses: pnpm/action-setup@v2.0.1
uses: pnpm/action-setup@v4
with:
version: latest

- name: Install Dependencies
run: pnpm install
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm run build
Expand All @@ -69,20 +73,20 @@ jobs:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Setup Node.js 18.x
uses: actions/setup-node@v2
- name: Setup Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: 18.x
node-version: ${{ env.NODE_VERSION }}

- name: Setup pnpm
uses: pnpm/action-setup@v2.0.1
uses: pnpm/action-setup@v4
with:
version: latest

- name: Install Dependencies
run: pnpm install
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm run build
Expand Down
13 changes: 8 additions & 5 deletions .github/workflows/server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
Expand All @@ -34,8 +34,11 @@ jobs:
- name: Install dependencies
run: composer install --prefer-dist --no-progress

- name: Run Lint
run: composer lint
- name: Run PHP CS Fixer Dry Run
run: composer test:lint

# - name: Run Tests -- Will add tests back after phppest issue https://github.com/pestphp/pest/issues/920 is fixed
# run: composer test:unit
- name: Run Static Analysis
run: composer test:types

- name: Run Tests
run: composer test:unit
1 change: 0 additions & 1 deletion .template-lintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ module.exports = {
rules: {
'no-invalid-interactive': 'off',
'no-yield-only': 'off',
'no-down-event-binding': 'off',
'table-groups': 'off',
'link-href-attributes': 'off',
'require-input-label': 'off',
Expand Down
75 changes: 66 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@

This monorepo contains both the frontend and backend components of the Pallet extension for Fleetbase. The frontend is built using Ember.js and the backend is implemented in PHP.

* PHP 7.3.0 or above
* Ember.js v4.8 or above
* Ember CLI v4.8 or above
* Node.js v18 or above
* PHP 8.0 or above
* Ember.js v5.4 or above
* Ember CLI v5.4 or above
* Node.js v22 for CI builds

## Structure

Expand Down Expand Up @@ -56,16 +56,72 @@ This monorepo contains both the frontend and backend components of the Pallet ex
Install the PHP packages using Composer:

```bash
composer require fleetbase/core-api
composer require fleetbase/fleetops
composer require fleetbase/pallet
composer require fleetbase/pallet-api
```
### Frontend

Install the Ember.js Engine/Addon:

```bash
pnpm install @fleetbase/pallet
pnpm install @fleetbase/pallet-engine
```

## Storefront Inventory Integration

Pallet is the canonical inventory authority for Storefront products. Storefront products and variants should be linked to Pallet products and variants by durable UUID fields, not by SKU alone:

* `pallet_products.storefront_product_uuid`
* `pallet_product_variants.storefront_variant_uuid`

SKU and barcode matching can be used for assisted lookup, but checkout enforcement should use the explicit Storefront link fields.

### Internal API Contract

All Storefront integration endpoints are scoped to the authenticated company under the protected internal API prefix:

```text
pallet/int/v1/storefront/inventory/resolve
pallet/int/v1/storefront/inventory/availability
pallet/int/v1/storefront/inventory/availability-batch
pallet/int/v1/storefront/inventory/link
pallet/int/v1/storefront/inventory/unlink
pallet/int/v1/storefront/inventory/reserve
pallet/int/v1/storefront/inventory/reserve-batch
pallet/int/v1/storefront/inventory/reservations/context
pallet/int/v1/storefront/inventory/reservations/{id}/release
pallet/int/v1/storefront/inventory/reservations/{id}/commit
pallet/int/v1/storefront/inventory/reservations/release-batch
pallet/int/v1/storefront/inventory/reservations/commit-batch
pallet/int/v1/storefront/inventory/reservations/release-context
pallet/int/v1/storefront/inventory/reservations/commit-context
```

Storefront should call `availability` or `availability-batch` when cart quantities change, `reserve` or `reserve-batch` when checkout starts, `release` when a checkout expires or is cancelled, and `commit` when an order is captured or fulfilled. Batch and context release/commit endpoints are available for checkout lifecycles that store reservation UUIDs directly or only retain a Storefront checkout/cart/order context. Context release can release expired active reservations so abandoned checkout stock is returned; context commit only uses non-expired active reservations. Availability responses include a stable `inventory_summary` object with total, available, reserved, out-of-stock, low-stock, reorder, Pallet UUID, and Storefront UUID fields.

Checkout reservations can include `storefront_checkout_uuid`, `storefront_cart_uuid`, `storefront_order_uuid`, `storefront_line_uuid`, and `storefront_reservation_key`. The reservation key is idempotent: retrying the same reservation key with the same quantity returns the existing active reservation; retrying it with a different quantity returns a conflict so checkout cannot double-reserve a cart line.

Product links can be created one product at a time:

```json
{
"pallet_product_uuid": "product_...",
"storefront_product_uuid": "..."
}
```

Variant links can be supplied individually with `pallet_variant_uuid` and `storefront_variant_uuid`, or in a batch:

```json
{
"pallet_product_uuid": "product_...",
"storefront_product_uuid": "...",
"variants": [
{
"pallet_variant_uuid": "variant_...",
"storefront_variant_uuid": "..."
}
]
}
```

## Usage
Expand All @@ -75,6 +131,7 @@ pnpm install @fleetbase/pallet
🧹 Keep a modern codebase with **PHP CS Fixer**:
```bash
composer lint
composer lint:fix
```

⚗️ Run static analysis using **PHPStan**:
Expand Down Expand Up @@ -120,4 +177,4 @@ pnpm build
See the Contributing Guide for details on how to contribute to this project.

## License
This project is licensed under the MIT License.
This project is licensed under the AGPL-3.0-or-later License.
1 change: 1 addition & 0 deletions addon/adapters/bin-location.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
1 change: 1 addition & 0 deletions addon/adapters/cycle-count-item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
1 change: 1 addition & 0 deletions addon/adapters/cycle-count.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
1 change: 1 addition & 0 deletions addon/adapters/inventory-reservation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
7 changes: 7 additions & 0 deletions addon/adapters/pallet-product-variant.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import PalletAdapter from './pallet';

export default class PalletProductVariantAdapter extends PalletAdapter {
pathForType() {
return 'product-variants';
}
}
1 change: 1 addition & 0 deletions addon/adapters/pick-list-item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
1 change: 1 addition & 0 deletions addon/adapters/pick-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
1 change: 1 addition & 0 deletions addon/adapters/purchase-order-item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
1 change: 1 addition & 0 deletions addon/adapters/sales-order-item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
1 change: 1 addition & 0 deletions addon/adapters/stock-transfer-item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
1 change: 1 addition & 0 deletions addon/adapters/stock-transfer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
1 change: 1 addition & 0 deletions addon/adapters/warehouse-zone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
1 change: 1 addition & 0 deletions addon/adapters/wave.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './pallet';
2 changes: 1 addition & 1 deletion addon/components/admin/product-category.hbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<ContentPanel @title="Categories" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
<div class="mt-3 flex items-center justify-end">
<Button @type="primary" @size="sm" @icon="plus" @text="Add category" @onClick={{this.addCategory}} @disabled={{this.isLoading}} @isLoading={{this.isLoading}} />
<Button @type="primary" @size="sm" @icon="plus" @text="Add category" @onClick={{this.addCategory}} />
</div>
<div class="mt-3">
<ul>
Expand Down
13 changes: 8 additions & 5 deletions addon/components/admin/product-category.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export default class AdminProductCategoryComponent extends Component {
@service hostRouter;
@tracked categories = [];
@tracked selectedCategory;
@tracked isLoading = false;
@tracked buttonTitle = null;

constructor() {
Expand All @@ -22,6 +21,10 @@ export default class AdminProductCategoryComponent extends Component {
this.fetchCategoryHierarchy();
}

getRecordUuid(record) {
return record?.uuid ?? record?.id;
}

@action async addCategory() {
const category = this.store.createRecord('category', {
for: 'pallet_product',
Expand All @@ -39,13 +42,13 @@ export default class AdminProductCategoryComponent extends Component {
file,
{
path: `uploads/${category.company_uuid}/product-category-icon/${dasherize(category.name ?? this.currentUser.companyId)}`,
subject_uuid: category.id,
subject_uuid: this.getRecordUuid(category),
subject_type: `category`,
type: `category_icon`,
},
(uploadedFile) => {
category.setProperties({
icon_file_uuid: uploadedFile.id,
icon_file_uuid: this.getRecordUuid(uploadedFile),
icon_url: uploadedFile.url,
icon: uploadedFile,
});
Expand Down Expand Up @@ -94,13 +97,13 @@ export default class AdminProductCategoryComponent extends Component {
file,
{
path: `uploads/${category.company_uuid}/product-category-icon/${dasherize(category.name ?? this.currentUser.companyId)}`,
subject_uuid: category.id,
subject_uuid: this.getRecordUuid(category),
subject_type: `category`,
type: `category_icon`,
},
(uploadedFile) => {
category.setProperties({
icon_file_uuid: uploadedFile.id,
icon_file_uuid: this.getRecordUuid(uploadedFile),
icon_url: uploadedFile.url,
icon: uploadedFile,
});
Expand Down
11 changes: 6 additions & 5 deletions addon/components/batch-form-panel.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@position="right"
@noBackdrop={{true}}
@fullHeight={{true}}
@isResizeble={{or this.isResizable @isResizable}}
@isResizable={{or this.isResizable @isResizable}}
@width={{or this.width @width "600px"}}
>
<Overlay::Header
Expand All @@ -18,8 +18,10 @@
@icon={{if this.batch.id "save" "check"}}
@type="primary"
@text={{if this.batch.id "Save Batch" "Add Batch"}}
@onClick={{this.save}}
@onClick={{perform this.saveTask}}
@wrapperClass="mr-2"
@isLoading={{this.saveTask.isRunning}}
@disabled={{this.saveTask.isRunning}}
/>
{{#if this.batch.id}}
<Button @type="default" @icon="batch" @helpText="View batch details" @onClick={{this.onViewDetails}} @wrapperClass="mr-2" />
Expand All @@ -38,8 +40,7 @@
@triggerClass="form-select form-input"
@infiniteScroll={{false}}
@renderInPlace={{true}}
@onChange={{fn (mut this.batch.product)}}
@onChangeId={{fn (mut this.batch.product_uuid)}}
@onChange={{this.setProduct}}
as |model|
>
{{model.name}}
Expand All @@ -52,4 +53,4 @@
</InputGroup>
</div>
</Overlay::Body>
</Overlay>
</Overlay>
Loading
Loading