+
+
\ No newline at end of file
diff --git a/addon/components/batch-panel.js b/addon/components/batch-panel.js
new file mode 100644
index 00000000..7e339641
--- /dev/null
+++ b/addon/components/batch-panel.js
@@ -0,0 +1,160 @@
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+import { isArray } from '@ember/array';
+import BatchPanelDetailsComponent from './batch-panel/details';
+import contextComponentCallback from '../utils/context-component-callback';
+import applyContextComponentArguments from '../utils/apply-context-component-arguments';
+
+export default class BatchPanelComponent extends Component {
+ /**
+ * Service for fetching data.
+ *
+ * @type {Service}
+ */
+ @service fetch;
+
+ /**
+ * Service for managing modals.
+ *
+ * @type {Service}
+ */
+ @service modalsManager;
+
+ /**
+ * Universe service for managing global data and settings.
+ *
+ * @type {Service}
+ */
+ @service universe;
+
+ /**
+ * Ember data store service.
+ *
+ * @type {Service}
+ */
+ @service store;
+
+ /**
+ * Service for managing routing within the host app.
+ *
+ * @type {Service}
+ */
+ @service hostRouter;
+
+ /**
+ * Service for managing the context panel.
+ *
+ * @type {Service}
+ */
+ @service contextPanel;
+
+ /**
+ * The current active tab.
+ *
+ * @type {Object}
+ * @tracked
+ */
+ @tracked tab;
+
+ /**
+ * The batch being displayed or edited.
+ *
+ * @type {batch}
+ * @tracked
+ */
+ @tracked batch;
+
+ /**
+ * Returns the array of tabs available for the panel.
+ *
+ * @type {Array}
+ */
+ get tabs() {
+ const registeredTabs = this.universe.getMenuItemsFromRegistry('component:batch-panel');
+ const defaultTabs = [this.universe._createMenuItem('Details', null, { icon: 'circle-info', component: BatchPanelDetailsComponent })];
+
+ if (isArray(registeredTabs)) {
+ return [...defaultTabs, ...registeredTabs];
+ }
+
+ return defaultTabs;
+ }
+
+ /**
+ * Initializes the batch panel component.
+ */
+ constructor() {
+ super(...arguments);
+ this.batch = this.args.batch;
+ this.tab = this.getTabUsingSlug(this.args.tab);
+ applyContextComponentArguments(this);
+ }
+
+ /**
+ * Sets the overlay context.
+ *
+ * @action
+ * @param {OverlayContextObject} overlayContext
+ */
+ @action setOverlayContext(overlayContext) {
+ this.context = overlayContext;
+ contextComponentCallback(this, 'onLoad', ...arguments);
+ }
+
+ /**
+ * Handles changing the active tab.
+ *
+ * @method
+ * @param {String} tab - The new tab to switch to.
+ * @action
+ */
+ @action onTabChanged(tab) {
+ this.tab = this.getTabUsingSlug(tab);
+ contextComponentCallback(this, 'onTabChanged', tab);
+ }
+
+ /**
+ * Handles edit action for the batch.
+ *
+ * @method
+ * @action
+ */
+ @action onEdit() {
+ const isActionOverrided = contextComponentCallback(this, 'onEdit', this.batch);
+
+ if (!isActionOverrided) {
+ this.contextPanel.focus(this.batch, 'editing', {
+ onAfterSave: () => {
+ this.contextPanel.clear();
+ },
+ });
+ }
+ }
+
+ /**
+ * Handles the cancel action.
+ *
+ * @method
+ * @action
+ * @returns {Boolean} Indicates whether the cancel action was overridden.
+ */
+ @action onPressCancel() {
+ return contextComponentCallback(this, 'onPressCancel', this.batch);
+ }
+
+ /**
+ * Finds and returns a tab based on its slug.
+ *
+ * @param {String} tabSlug - The slug of the tab.
+ * @returns {Object|null} The found tab or null.
+ */
+ getTabUsingSlug(tabSlug) {
+ if (tabSlug) {
+ return this.tabs.find(({ slug }) => slug === tabSlug);
+ }
+
+ return this.tabs[0];
+ }
+}
diff --git a/addon/components/batch-panel/details.hbs b/addon/components/batch-panel/details.hbs
new file mode 100644
index 00000000..fdf571d1
--- /dev/null
+++ b/addon/components/batch-panel/details.hbs
@@ -0,0 +1,22 @@
+
+
+
+
+
ID
+
{{n-a @batch.public_id}}
+
+
+
Product
+
{{n-a @batch.product.name}}
+
+
+
Batch Number
+
{{n-a @batch.batch_number}}
+
+
+
Quantity
+
{{n-a @batch.quantity}}
+
+
+
+
\ No newline at end of file
diff --git a/addon/components/cell/product-info.hbs b/addon/components/cell/product-info.hbs
new file mode 100644
index 00000000..48c8d039
--- /dev/null
+++ b/addon/components/cell/product-info.hbs
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/addon/components/inventory-panel.js b/addon/components/inventory-panel.js
new file mode 100644
index 00000000..a15c4be1
--- /dev/null
+++ b/addon/components/inventory-panel.js
@@ -0,0 +1,160 @@
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+import { isArray } from '@ember/array';
+import InventoryPanelDetailsComponent from './inventory-panel/details';
+import contextComponentCallback from '../utils/context-component-callback';
+import applyContextComponentArguments from '../utils/apply-context-component-arguments';
+
+export default class InventoryPanelComponent extends Component {
+ /**
+ * Service for fetching data.
+ *
+ * @type {Service}
+ */
+ @service fetch;
+
+ /**
+ * Service for managing modals.
+ *
+ * @type {Service}
+ */
+ @service modalsManager;
+
+ /**
+ * Universe service for managing global data and settings.
+ *
+ * @type {Service}
+ */
+ @service universe;
+
+ /**
+ * Ember data store service.
+ *
+ * @type {Service}
+ */
+ @service store;
+
+ /**
+ * Service for managing routing within the host app.
+ *
+ * @type {Service}
+ */
+ @service hostRouter;
+
+ /**
+ * Service for managing the context panel.
+ *
+ * @type {Service}
+ */
+ @service contextPanel;
+
+ /**
+ * The current active tab.
+ *
+ * @type {Object}
+ * @tracked
+ */
+ @tracked tab;
+
+ /**
+ * The inventory being displayed or edited.
+ *
+ * @type {inventory}
+ * @tracked
+ */
+ @tracked inventory;
+
+ /**
+ * Returns the array of tabs available for the panel.
+ *
+ * @type {Array}
+ */
+ get tabs() {
+ const registeredTabs = this.universe.getMenuItemsFromRegistry('component:inventory-panel');
+ const defaultTabs = [this.universe._createMenuItem('Details', null, { icon: 'circle-info', component: InventoryPanelDetailsComponent })];
+
+ if (isArray(registeredTabs)) {
+ return [...defaultTabs, ...registeredTabs];
+ }
+
+ return defaultTabs;
+ }
+
+ /**
+ * Initializes the inventory panel component.
+ */
+ constructor() {
+ super(...arguments);
+ this.inventory = this.args.inventory;
+ this.tab = this.getTabUsingSlug(this.args.tab);
+ applyContextComponentArguments(this);
+ }
+
+ /**
+ * Sets the overlay context.
+ *
+ * @action
+ * @param {OverlayContextObject} overlayContext
+ */
+ @action setOverlayContext(overlayContext) {
+ this.context = overlayContext;
+ contextComponentCallback(this, 'onLoad', ...arguments);
+ }
+
+ /**
+ * Handles changing the active tab.
+ *
+ * @method
+ * @param {String} tab - The new tab to switch to.
+ * @action
+ */
+ @action onTabChanged(tab) {
+ this.tab = this.getTabUsingSlug(tab);
+ contextComponentCallback(this, 'onTabChanged', tab);
+ }
+
+ /**
+ * Handles edit action for the inventory.
+ *
+ * @method
+ * @action
+ */
+ @action onEdit() {
+ const isActionOverrided = contextComponentCallback(this, 'onEdit', this.inventory);
+
+ if (!isActionOverrided) {
+ this.contextPanel.focus(this.inventory, 'editing', {
+ onAfterSave: () => {
+ this.contextPanel.clear();
+ },
+ });
+ }
+ }
+
+ /**
+ * Handles the cancel action.
+ *
+ * @method
+ * @action
+ * @returns {Boolean} Indicates whether the cancel action was overridden.
+ */
+ @action onPressCancel() {
+ return contextComponentCallback(this, 'onPressCancel', this.inventory);
+ }
+
+ /**
+ * Finds and returns a tab based on its slug.
+ *
+ * @param {String} tabSlug - The slug of the tab.
+ * @returns {Object|null} The found tab or null.
+ */
+ getTabUsingSlug(tabSlug) {
+ if (tabSlug) {
+ return this.tabs.find(({ slug }) => slug === tabSlug);
+ }
+
+ return this.tabs[0];
+ }
+}
diff --git a/addon/components/inventory-panel/details.hbs b/addon/components/inventory-panel/details.hbs
new file mode 100644
index 00000000..c201aeb3
--- /dev/null
+++ b/addon/components/inventory-panel/details.hbs
@@ -0,0 +1,34 @@
+
+
+
+
+
ID
+
{{n-a @inventory.public_id}}
+
+
+
Warehouse
+
{{n-a @inventory.warehouse.name}}
+
+
+
Product
+
{{n-a @inventory.product.name}}
+
+
+
Batch
+
{{n-a @inventory.batch.batch_number}}
+
+
+
Supplier
+
{{n-a @inventory.supplier.name}}
+
+
+
Expiry Date
+
{{n-a @inventory.expiry_date_at}}
+
+
+
Manufactured Date
+
{{n-a @inventory.created_at}}
+
+
+
+
\ No newline at end of file
diff --git a/addon/components/product-form-panel.hbs b/addon/components/product-form-panel.hbs
new file mode 100644
index 00000000..d975fdbb
--- /dev/null
+++ b/addon/components/product-form-panel.hbs
@@ -0,0 +1,234 @@
+
+
+
+
+ {{#if this.product.id}}
+
+ {{/if}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{smart-humanize category}}
+
+
+
+
+
+ {{model.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{#if this.isUploading}}
+
+
+
+
+
+ {{else}}
+ {{#let (file-queue name="files" onFileAdded=this.queueFile accept=(join "," this.acceptedFileTypes)) as |queue|}}
+
+ {{#if dropzone.active}}
+ {{#if dropzone.valid}}
+ Drop to upload
+ {{else}}
+ Invalid
+ {{/if}}
+ {{else if queue.files.length}}
+
+
+ {{pluralize queue.files.length "file"}}
+ ready for upload.
+
\ No newline at end of file
diff --git a/addon/components/purchase-order-form-panel.hbs b/addon/components/purchase-order-form-panel.hbs
new file mode 100644
index 00000000..93535239
--- /dev/null
+++ b/addon/components/purchase-order-form-panel.hbs
@@ -0,0 +1,75 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/addon/components/purchase-order-panel.js b/addon/components/purchase-order-panel.js
new file mode 100644
index 00000000..5b940b34
--- /dev/null
+++ b/addon/components/purchase-order-panel.js
@@ -0,0 +1,160 @@
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+import { isArray } from '@ember/array';
+import PurchaseOrderPanelDetailsComponent from './purchase-order-panel/details';
+import contextComponentCallback from '../utils/context-component-callback';
+import applyContextComponentArguments from '../utils/apply-context-component-arguments';
+
+export default class PurchaseOrderPanelComponent extends Component {
+ /**
+ * Service for fetching data.
+ *
+ * @type {Service}
+ */
+ @service fetch;
+
+ /**
+ * Service for managing modals.
+ *
+ * @type {Service}
+ */
+ @service modalsManager;
+
+ /**
+ * Universe service for managing global data and settings.
+ *
+ * @type {Service}
+ */
+ @service universe;
+
+ /**
+ * Ember data store service.
+ *
+ * @type {Service}
+ */
+ @service store;
+
+ /**
+ * Service for managing routing within the host app.
+ *
+ * @type {Service}
+ */
+ @service hostRouter;
+
+ /**
+ * Service for managing the context panel.
+ *
+ * @type {Service}
+ */
+ @service contextPanel;
+
+ /**
+ * The current active tab.
+ *
+ * @type {Object}
+ * @tracked
+ */
+ @tracked tab;
+
+ /**
+ * The purchase-order being displayed or edited.
+ *
+ * @type {purchaseOrder}
+ * @tracked
+ */
+ @tracked purchaseOrder;
+
+ /**
+ * Returns the array of tabs available for the panel.
+ *
+ * @type {Array}
+ */
+ get tabs() {
+ const registeredTabs = this.universe.getMenuItemsFromRegistry('component:purchase-order-panel');
+ const defaultTabs = [this.universe._createMenuItem('Details', null, { icon: 'circle-info', component: PurchaseOrderPanelDetailsComponent })];
+
+ if (isArray(registeredTabs)) {
+ return [...defaultTabs, ...registeredTabs];
+ }
+
+ return defaultTabs;
+ }
+
+ /**
+ * Initializes the purchase-order panel component.
+ */
+ constructor() {
+ super(...arguments);
+ this.purchaseOrder = this.args.purchaseOrder;
+ this.tab = this.getTabUsingSlug(this.args.tab);
+ applyContextComponentArguments(this);
+ }
+
+ /**
+ * Sets the overlay context.
+ *
+ * @action
+ * @param {OverlayContextObject} overlayContext
+ */
+ @action setOverlayContext(overlayContext) {
+ this.context = overlayContext;
+ contextComponentCallback(this, 'onLoad', ...arguments);
+ }
+
+ /**
+ * Handles changing the active tab.
+ *
+ * @method
+ * @param {String} tab - The new tab to switch to.
+ * @action
+ */
+ @action onTabChanged(tab) {
+ this.tab = this.getTabUsingSlug(tab);
+ contextComponentCallback(this, 'onTabChanged', tab);
+ }
+
+ /**
+ * Handles edit action for the purchase-order.
+ *
+ * @method
+ * @action
+ */
+ @action onEdit() {
+ const isActionOverrided = contextComponentCallback(this, 'onEdit', this.purchaseOrder);
+
+ if (!isActionOverrided) {
+ this.contextPanel.focus(this.purchaseOrder, 'editing', {
+ onAfterSave: () => {
+ this.contextPanel.clear();
+ },
+ });
+ }
+ }
+
+ /**
+ * Handles the cancel action.
+ *
+ * @method
+ * @action
+ * @returns {Boolean} Indicates whether the cancel action was overridden.
+ */
+ @action onPressCancel() {
+ return contextComponentCallback(this, 'onPressCancel', this.purchaseOrder);
+ }
+
+ /**
+ * Finds and returns a tab based on its slug.
+ *
+ * @param {String} tabSlug - The slug of the tab.
+ * @returns {Object|null} The found tab or null.
+ */
+ getTabUsingSlug(tabSlug) {
+ if (tabSlug) {
+ return this.tabs.find(({ slug }) => slug === tabSlug);
+ }
+
+ return this.tabs[0];
+ }
+}
diff --git a/addon/components/purchase-order-panel/details.hbs b/addon/components/purchase-order-panel/details.hbs
new file mode 100644
index 00000000..632dcad0
--- /dev/null
+++ b/addon/components/purchase-order-panel/details.hbs
@@ -0,0 +1,42 @@
+
+
+
+
+
ID
+
{{n-a @purchaseOrder.public_id}}
+
+
+
Supplier
+
{{n-a @purchaseOrder.supplier.name}}
+
+
+
Reference Code
+
{{n-a @purchaseOrder.reference_code}}
+
+
+
Reference URL
+
{{n-a @purchaseOrder.reference_url}}
+
+
+
Description
+
{{n-a @purchaseOrder.description}}
+
+
+
Comments
+
{{n-a @purchaseOrder.comments}}
+
+
+
Status
+
{{n-a @purchaseOrder.status}}
+
+
+
Order Created At
+
{{n-a @purchaseOrder.created_at}}
+
+
+
Expected Delivery At
+
{{n-a @purchaseOrder.expected_delivery_at}}
+
+
+
+
\ No newline at end of file
diff --git a/addon/components/sales-order-form-panel.hbs b/addon/components/sales-order-form-panel.hbs
new file mode 100644
index 00000000..5c744f94
--- /dev/null
+++ b/addon/components/sales-order-form-panel.hbs
@@ -0,0 +1,75 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/addon/components/sales-order-panel.js b/addon/components/sales-order-panel.js
new file mode 100644
index 00000000..21ce38a7
--- /dev/null
+++ b/addon/components/sales-order-panel.js
@@ -0,0 +1,160 @@
+import Component from '@glimmer/component';
+import { tracked } from '@glimmer/tracking';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+import { isArray } from '@ember/array';
+import SalesOrderPanelDetailsComponent from './sales-order-panel/details';
+import contextComponentCallback from '../utils/context-component-callback';
+import applyContextComponentArguments from '../utils/apply-context-component-arguments';
+
+export default class SalesOrderPanelComponent extends Component {
+ /**
+ * Service for fetching data.
+ *
+ * @type {Service}
+ */
+ @service fetch;
+
+ /**
+ * Service for managing modals.
+ *
+ * @type {Service}
+ */
+ @service modalsManager;
+
+ /**
+ * Universe service for managing global data and settings.
+ *
+ * @type {Service}
+ */
+ @service universe;
+
+ /**
+ * Ember data store service.
+ *
+ * @type {Service}
+ */
+ @service store;
+
+ /**
+ * Service for managing routing within the host app.
+ *
+ * @type {Service}
+ */
+ @service hostRouter;
+
+ /**
+ * Service for managing the context panel.
+ *
+ * @type {Service}
+ */
+ @service contextPanel;
+
+ /**
+ * The current active tab.
+ *
+ * @type {Object}
+ * @tracked
+ */
+ @tracked tab;
+
+ /**
+ * The sales-order being displayed or edited.
+ *
+ * @type {salesOrder}
+ * @tracked
+ */
+ @tracked salesOrder;
+
+ /**
+ * Returns the array of tabs available for the panel.
+ *
+ * @type {Array}
+ */
+ get tabs() {
+ const registeredTabs = this.universe.getMenuItemsFromRegistry('component:sales-order-panel');
+ const defaultTabs = [this.universe._createMenuItem('Details', null, { icon: 'circle-info', component: SalesOrderPanelDetailsComponent })];
+
+ if (isArray(registeredTabs)) {
+ return [...defaultTabs, ...registeredTabs];
+ }
+
+ return defaultTabs;
+ }
+
+ /**
+ * Initializes the sales-order panel component.
+ */
+ constructor() {
+ super(...arguments);
+ this.salesOrder = this.args.salesOrder;
+ this.tab = this.getTabUsingSlug(this.args.tab);
+ applyContextComponentArguments(this);
+ }
+
+ /**
+ * Sets the overlay context.
+ *
+ * @action
+ * @param {OverlayContextObject} overlayContext
+ */
+ @action setOverlayContext(overlayContext) {
+ this.context = overlayContext;
+ contextComponentCallback(this, 'onLoad', ...arguments);
+ }
+
+ /**
+ * Handles changing the active tab.
+ *
+ * @method
+ * @param {String} tab - The new tab to switch to.
+ * @action
+ */
+ @action onTabChanged(tab) {
+ this.tab = this.getTabUsingSlug(tab);
+ contextComponentCallback(this, 'onTabChanged', tab);
+ }
+
+ /**
+ * Handles edit action for the sales-order.
+ *
+ * @method
+ * @action
+ */
+ @action onEdit() {
+ const isActionOverrided = contextComponentCallback(this, 'onEdit', this.salesOrder);
+
+ if (!isActionOverrided) {
+ this.contextPanel.focus(this.salesOrder, 'editing', {
+ onAfterSave: () => {
+ this.contextPanel.clear();
+ },
+ });
+ }
+ }
+
+ /**
+ * Handles the cancel action.
+ *
+ * @method
+ * @action
+ * @returns {Boolean} Indicates whether the cancel action was overridden.
+ */
+ @action onPressCancel() {
+ return contextComponentCallback(this, 'onPressCancel', this.salesOrder);
+ }
+
+ /**
+ * Finds and returns a tab based on its slug.
+ *
+ * @param {String} tabSlug - The slug of the tab.
+ * @returns {Object|null} The found tab or null.
+ */
+ getTabUsingSlug(tabSlug) {
+ if (tabSlug) {
+ return this.tabs.find(({ slug }) => slug === tabSlug);
+ }
+
+ return this.tabs[0];
+ }
+}
diff --git a/addon/components/sales-order-panel/details.hbs b/addon/components/sales-order-panel/details.hbs
new file mode 100644
index 00000000..0c35776a
--- /dev/null
+++ b/addon/components/sales-order-panel/details.hbs
@@ -0,0 +1,42 @@
+
+
+
+
+
ID
+
{{n-a @salesOrder.public_id}}
+
+
+
Status
+
{{n-a @salesOrder.status}}
+
+
+
Supplier
+
{{n-a @salesOrder.supplier.name}}
+
+
+
Reference Code
+
{{n-a @salesOrder.reference_code}}
+
+
+
Reference URL
+
{{n-a @salesOrder.reference_url}}
+
+
+
Description
+
{{n-a @salesOrder.description}}
+
+
+
Comments
+
{{n-a @salesOrder.comments}}
+
+
+
Order Date
+
{{n-a @salesOrder.created_at}}
+
+
+
Delivery Date
+
{{n-a @salesOrder.expected_delivery_at}}
+
+
+
+
\ No newline at end of file
diff --git a/addon/components/stock-adjustment-form-panel.hbs b/addon/components/stock-adjustment-form-panel.hbs
new file mode 100644
index 00000000..29f4b78a
--- /dev/null
+++ b/addon/components/stock-adjustment-form-panel.hbs
@@ -0,0 +1,67 @@
+
+
+