customer orders Module
This commit is contained in:
parent
f638146824
commit
b1b0396c72
|
|
@ -3,6 +3,7 @@ import { useService } from "@web/core/utils/hooks";
|
||||||
import { standardActionServiceProps } from "@web/webclient/actions/action_service";
|
import { standardActionServiceProps } from "@web/webclient/actions/action_service";
|
||||||
import { registry } from "@web/core/registry";
|
import { registry } from "@web/core/registry";
|
||||||
import { Component, onMounted, useRef, onWillStart, useState } from "@odoo/owl";
|
import { Component, onMounted, useRef, onWillStart, useState } from "@odoo/owl";
|
||||||
|
import { loadCSS } from '@web/core/assets';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -18,6 +19,11 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
this.notification = useService("notification");
|
this.notification = useService("notification");
|
||||||
this.action = useService("action");
|
this.action = useService("action");
|
||||||
|
|
||||||
|
const currentDate = new Date();
|
||||||
|
const currentMonth = String(currentDate.getMonth() + 1).padStart(2, '0');
|
||||||
|
const currentYear = currentDate.getFullYear();
|
||||||
|
const currentMonthYear = `${currentYear}-${currentMonth}`;
|
||||||
|
|
||||||
this.state = useState({
|
this.state = useState({
|
||||||
// Active tab
|
// Active tab
|
||||||
activeTab: 'order',
|
activeTab: 'order',
|
||||||
|
|
@ -63,7 +69,8 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
totalOrderQty: 0,
|
totalOrderQty: 0,
|
||||||
totalFgAvailable: 0,
|
totalFgAvailable: 0,
|
||||||
totalRemainingProduction: 0
|
totalRemainingProduction: 0
|
||||||
}
|
},
|
||||||
|
selectedMonthYear:currentMonthYear
|
||||||
});
|
});
|
||||||
|
|
||||||
this.orderGridRef = useRef('orderGrid');
|
this.orderGridRef = useRef('orderGrid');
|
||||||
|
|
@ -73,6 +80,7 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
|
|
||||||
onWillStart(async () => {
|
onWillStart(async () => {
|
||||||
await this.loadGridData();
|
await this.loadGridData();
|
||||||
|
// await loadCSS('/web_grid/static/lib/pq_grid/themes/gray/pqgrid.css')
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -82,6 +90,26 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMonthYearChange(event) {
|
||||||
|
this.state.selectedMonthYear = event.target.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearFilter() {
|
||||||
|
this.state.selectedMonthYear = '';
|
||||||
|
this.loadGridData();
|
||||||
|
this.notification.add("Filter cleared", { type: "success" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to format month/year label
|
||||||
|
getMonthYearLabel() {
|
||||||
|
if (!this.state.selectedMonthYear) return '';
|
||||||
|
const [year, month] = this.state.selectedMonthYear.split('-');
|
||||||
|
const monthNames = [
|
||||||
|
'January', 'February', 'March', 'April', 'May', 'June',
|
||||||
|
'July', 'August', 'September', 'October', 'November', 'December'
|
||||||
|
];
|
||||||
|
return `${monthNames[parseInt(month) - 1]} ${year}`;
|
||||||
|
}
|
||||||
// Helper functions - make them available to template
|
// Helper functions - make them available to template
|
||||||
formatFloat(value) {
|
formatFloat(value) {
|
||||||
if (value === null || value === undefined || isNaN(value)) {
|
if (value === null || value === undefined || isNaN(value)) {
|
||||||
|
|
@ -119,12 +147,21 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
async loadGridData() {
|
async loadGridData() {
|
||||||
this.state.isLoading = true;
|
this.state.isLoading = true;
|
||||||
try {
|
try {
|
||||||
const data = await this.orm.call(
|
let month = '';
|
||||||
"cor.dashboard",
|
let year = '';
|
||||||
"get_customer_order_status_data",
|
|
||||||
[[]],
|
// If filter is set, use it
|
||||||
{}
|
if (this.state.selectedMonthYear) {
|
||||||
);
|
[year, month] = this.state.selectedMonthYear.split('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await this.orm.call(
|
||||||
|
"cor.dashboard",
|
||||||
|
"get_customer_order_status_data",
|
||||||
|
[month,year],
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
let totalOrderQty = 0;
|
let totalOrderQty = 0;
|
||||||
let totalProducedQty = 0;
|
let totalProducedQty = 0;
|
||||||
|
|
@ -184,10 +221,18 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
async loadDispatchSummary() {
|
async loadDispatchSummary() {
|
||||||
this.state.dispatchLoading = true;
|
this.state.dispatchLoading = true;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
let month = '';
|
||||||
|
let year = '';
|
||||||
|
|
||||||
|
// If filter is set, use it
|
||||||
|
if (this.state.selectedMonthYear) {
|
||||||
|
[year, month] = this.state.selectedMonthYear.split('-');
|
||||||
|
}
|
||||||
const data = await this.orm.call(
|
const data = await this.orm.call(
|
||||||
"cor.dashboard",
|
"cor.dashboard",
|
||||||
"get_dispatch_summary_data",
|
"get_dispatch_summary_data",
|
||||||
[[]],
|
[month,year],
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -198,10 +243,11 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
|
|
||||||
const processedData = data.map(row => {
|
const processedData = data.map(row => {
|
||||||
const orderQty = parseFloat(row.order_qty) || 0;
|
const orderQty = parseFloat(row.order_qty) || 0;
|
||||||
const dispatchedQty = parseFloat(row.dispatched_qty) || 0;
|
const dispatchedQty = parseFloat(row.invoiced_qty) || 0;
|
||||||
const balanceQty = Math.max(0, orderQty - dispatchedQty);
|
const balanceQty = Math.max(0, orderQty - dispatchedQty);
|
||||||
const dispatchStatus = balanceQty === 0 ? "Full" : "Partial";
|
const dispatchStatus = balanceQty === 0 ? "Full" : "Partial";
|
||||||
|
|
||||||
|
|
||||||
totalOrders++;
|
totalOrders++;
|
||||||
if (dispatchStatus === "Full") {
|
if (dispatchStatus === "Full") {
|
||||||
fullDispatch++;
|
fullDispatch++;
|
||||||
|
|
@ -248,10 +294,18 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
async loadRMAvailability() {
|
async loadRMAvailability() {
|
||||||
this.state.rmLoading = true;
|
this.state.rmLoading = true;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
let month = '';
|
||||||
|
let year = '';
|
||||||
|
|
||||||
|
// If filter is set, use it
|
||||||
|
if (this.state.selectedMonthYear) {
|
||||||
|
[year, month] = this.state.selectedMonthYear.split('-');
|
||||||
|
}
|
||||||
const data = await this.orm.call(
|
const data = await this.orm.call(
|
||||||
"cor.dashboard",
|
"cor.dashboard",
|
||||||
"get_raw_material_availability_data",
|
"get_raw_material_availability_data",
|
||||||
[[]],
|
[year, month],
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -411,10 +465,12 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$(this.orderGridRef.el).pqGrid({
|
$(this.orderGridRef.el).pqGrid({
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: 500,
|
height: 500,
|
||||||
title: "Customer Order Status",
|
title: "Customer Order Status",
|
||||||
|
editable:false,
|
||||||
dataModel: {
|
dataModel: {
|
||||||
data: this.state.gridData,
|
data: this.state.gridData,
|
||||||
location: "local",
|
location: "local",
|
||||||
|
|
@ -422,15 +478,7 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
paging: "local",
|
paging: "local",
|
||||||
rPP: 50
|
rPP: 50
|
||||||
},
|
},
|
||||||
groupModel: {
|
|
||||||
on: true,
|
|
||||||
dataIndx: ['customer'],
|
|
||||||
collapsed: [false],
|
|
||||||
merge: true,
|
|
||||||
showSummary: [true],
|
|
||||||
grandSummary: true,
|
|
||||||
summaryTitle: 'Subtotal:'
|
|
||||||
},
|
|
||||||
summaryModel: {
|
summaryModel: {
|
||||||
on: true,
|
on: true,
|
||||||
type: 'top',
|
type: 'top',
|
||||||
|
|
@ -452,53 +500,147 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
},
|
},
|
||||||
numberCell: { show: true, title: "#", width: 60 },
|
numberCell: { show: true, title: "#", width: 60 },
|
||||||
freezeCols: 2,
|
freezeCols: 2,
|
||||||
style: {
|
|
||||||
border: '1px solid #dee2e6',
|
|
||||||
borderRadius: '4px'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const groupModel = {
|
||||||
|
on: true,
|
||||||
|
dataIndx: ['customer'],
|
||||||
|
collapsed: [false],
|
||||||
|
merge: true,
|
||||||
|
showSummary: [true],
|
||||||
|
grandSummary: true,
|
||||||
|
summaryTitle: 'Subtotal:'
|
||||||
|
}
|
||||||
|
$(this.orderGridRef.el).pqGrid("groupOption", groupModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeDispatchGrid() {
|
initializeDispatchGrid() {
|
||||||
if (this.dispatchGridRef.el && this.state.dispatchData.length > 0) {
|
if (!this.dispatchGridRef.el || this.state.dispatchData.length === 0) {
|
||||||
const columns = this.getDispatchGridColumns();
|
return;
|
||||||
|
|
||||||
if (typeof window.$ === 'undefined' || typeof window.pq === 'undefined') {
|
|
||||||
console.warn('jQuery or paramQuery not loaded');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(this.dispatchGridRef.el).pqGrid({
|
|
||||||
width: "100%",
|
|
||||||
height: 500,
|
|
||||||
title: "Dispatch Summary",
|
|
||||||
dataModel: {
|
|
||||||
data: this.state.dispatchData,
|
|
||||||
location: "local",
|
|
||||||
sorting: "local",
|
|
||||||
paging: "local",
|
|
||||||
rPP: 20
|
|
||||||
},
|
|
||||||
colModel: columns,
|
|
||||||
numberCell: { show: true, title: "#", width: 40 },
|
|
||||||
scrollModel: { autoFit: true },
|
|
||||||
freezeCols: 3,
|
|
||||||
filterModel: {
|
|
||||||
on: true,
|
|
||||||
mode: "AND",
|
|
||||||
header: true,
|
|
||||||
autoSearch: true,
|
|
||||||
type: 'local'
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
border: '1px solid #dee2e6',
|
|
||||||
borderRadius: '4px'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof window.$ === 'undefined' || typeof window.pq === 'undefined') {
|
||||||
|
console.warn('jQuery or paramQuery not loaded');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const agg = pq.aggregate;
|
||||||
|
agg.sum_ = function(arr, col) {
|
||||||
|
return " " + agg.sum(arr, col).toFixed(2).toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 1. Collect unique invoice dates from query result
|
||||||
|
// --------------------------------------------------
|
||||||
|
const dateSet = new Set();
|
||||||
|
|
||||||
|
this.state.dispatchData.forEach(row => {
|
||||||
|
(row.invoice_date_qty || []).forEach(d => {
|
||||||
|
dateSet.add(d.invoice_date);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const dateColumns = Array.from(dateSet).sort();
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 2. Flatten date-wise quantities into row object
|
||||||
|
// --------------------------------------------------
|
||||||
|
this.state.dispatchData.forEach(row => {
|
||||||
|
(row.invoice_date_qty || []).forEach(d => {
|
||||||
|
row[d.invoice_date] = d.qty;
|
||||||
|
});
|
||||||
|
delete row.invoice_date_qty;
|
||||||
|
});
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 3. Base columns
|
||||||
|
// --------------------------------------------------
|
||||||
|
const columns = this.getDispatchGridColumns();
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 4. Dynamic date columns from query
|
||||||
|
// --------------------------------------------------
|
||||||
|
dateColumns.forEach(date => {
|
||||||
|
const [year, month, day] = date.split('-');
|
||||||
|
columns.push({
|
||||||
|
title: `${day}/${month}/${year}`, // day only
|
||||||
|
dataIndx: date,
|
||||||
|
width: 100,
|
||||||
|
align: "right",
|
||||||
|
dataType: "float",
|
||||||
|
summary: { type: "sum_" }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 5. Destroy existing grid (important)
|
||||||
|
// --------------------------------------------------
|
||||||
|
const $grid = $(this.dispatchGridRef.el);
|
||||||
|
if ($grid.data("pqGrid")) {
|
||||||
|
$grid.pqGrid("destroy");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// 6. Initialize ParamQuery Grid
|
||||||
|
// --------------------------------------------------
|
||||||
|
$grid.pqGrid({
|
||||||
|
width: "100%",
|
||||||
|
height: 600,
|
||||||
|
title: "Dispatch Summary",
|
||||||
|
editable:false,
|
||||||
|
|
||||||
|
dataModel: {
|
||||||
|
data: this.state.dispatchData,
|
||||||
|
location: "local",
|
||||||
|
sorting: "local",
|
||||||
|
paging: "local",
|
||||||
|
rPP: 20
|
||||||
|
},
|
||||||
|
|
||||||
|
colModel: columns,
|
||||||
|
|
||||||
|
numberCell: {
|
||||||
|
show: true,
|
||||||
|
title: "#",
|
||||||
|
width: 40
|
||||||
|
},
|
||||||
|
|
||||||
|
freezeCols: 4,
|
||||||
|
summaryModel: {
|
||||||
|
on: true,
|
||||||
|
type: 'top',
|
||||||
|
title: 'Grand Total:',
|
||||||
|
col: ['order_qty', 'invoiced_qty']
|
||||||
|
},
|
||||||
|
|
||||||
|
filterModel: {
|
||||||
|
on: true,
|
||||||
|
mode: "AND",
|
||||||
|
header: true,
|
||||||
|
autoSearch: true,
|
||||||
|
type: "local"
|
||||||
|
},
|
||||||
|
|
||||||
|
style: {
|
||||||
|
border: "1px solid #dee2e6",
|
||||||
|
borderRadius: "4px"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const groupModel = {
|
||||||
|
on: true,
|
||||||
|
dataIndx: ['customer'],
|
||||||
|
collapsed: [false],
|
||||||
|
merge: true,
|
||||||
|
showSummary: [true,false],
|
||||||
|
grandSummary: true,
|
||||||
|
summaryTitle: 'Subtotal:'
|
||||||
|
|
||||||
|
}
|
||||||
|
$grid.pqGrid("groupOption", groupModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
initializeRMGrid() {
|
initializeRMGrid() {
|
||||||
if (this.rmGridRef.el && this.state.rmData.length > 0) {
|
if (this.rmGridRef.el && this.state.rmData.length > 0) {
|
||||||
const columns = this.getRMGridColumns();
|
const columns = this.getRMGridColumns();
|
||||||
|
|
@ -522,6 +664,7 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
colModel: columns,
|
colModel: columns,
|
||||||
numberCell: { show: true, title: "#", width: 30 },
|
numberCell: { show: true, title: "#", width: 30 },
|
||||||
scrollModel: { autoFit: true },
|
scrollModel: { autoFit: true },
|
||||||
|
editable:false,
|
||||||
freezeCols: 1,
|
freezeCols: 1,
|
||||||
filterModel: {
|
filterModel: {
|
||||||
on: true,
|
on: true,
|
||||||
|
|
@ -551,6 +694,7 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: 500,
|
height: 500,
|
||||||
title: "Daily Production Report",
|
title: "Daily Production Report",
|
||||||
|
editable:false,
|
||||||
dataModel: {
|
dataModel: {
|
||||||
data: this.state.dprData,
|
data: this.state.dprData,
|
||||||
location: "local",
|
location: "local",
|
||||||
|
|
@ -786,11 +930,22 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMonthDates(year, month) {
|
||||||
|
const dates = [];
|
||||||
|
const date = new Date(year, month - 1, 1);
|
||||||
|
|
||||||
|
while (date.getMonth() === month - 1) {
|
||||||
|
dates.push(new Date(date));
|
||||||
|
date.setDate(date.getDate() + 1);
|
||||||
|
}
|
||||||
|
return dates;
|
||||||
|
}
|
||||||
|
|
||||||
getDispatchGridColumns() {
|
getDispatchGridColumns() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: "Customer",
|
title: "Customer",
|
||||||
width: 120,
|
width: 220,
|
||||||
dataIndx: "customer",
|
dataIndx: "customer",
|
||||||
dataType: "string",
|
dataType: "string",
|
||||||
align: "left",
|
align: "left",
|
||||||
|
|
@ -799,7 +954,7 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Product",
|
title: "Product",
|
||||||
width: 100,
|
width: 250,
|
||||||
dataIndx: "product",
|
dataIndx: "product",
|
||||||
dataType: "string",
|
dataType: "string",
|
||||||
align: "left",
|
align: "left",
|
||||||
|
|
@ -808,53 +963,109 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Order Qty",
|
title: "Order Qty",
|
||||||
width: 60,
|
colModel: [
|
||||||
dataIndx: "order_qty",
|
{
|
||||||
dataType: "float",
|
title: "Bags",
|
||||||
align: "right",
|
width: 90,
|
||||||
render: (ui) => this.formatInteger(ui.cellData),
|
dataIndx: "order_qty",
|
||||||
frozen: true,
|
dataType: "float",
|
||||||
style: { backgroundColor: '#e3f2fd', textAlign: 'right' }
|
filter: true,
|
||||||
|
sortable: true,
|
||||||
|
align: "right",
|
||||||
|
render: (ui) => this.formatInteger(ui.cellData),
|
||||||
|
summary: {
|
||||||
|
type: "sum",
|
||||||
|
label: "Total:",
|
||||||
|
render: (ui) => this.formatInteger(ui.data)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Kgs",
|
||||||
|
width: 90,
|
||||||
|
dataIndx: "order_qty_kg",
|
||||||
|
dataType: "float",
|
||||||
|
filter: true,
|
||||||
|
sortable: true,
|
||||||
|
align: "right",
|
||||||
|
render: (ui) => this.formatFloat(ui.cellData),
|
||||||
|
summary: {
|
||||||
|
type: "sum",
|
||||||
|
label: "Total:",
|
||||||
|
render: (ui) => this.formatFloat(ui.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Dispatched Qty",
|
title: "Dispatched Qty",
|
||||||
width: 60,
|
colModel: [
|
||||||
dataIndx: "dispatched_qty",
|
{
|
||||||
dataType: "float",
|
title: "Bags",
|
||||||
align: "right",
|
width: 90,
|
||||||
render: (ui) => this.formatInteger(ui.cellData),
|
dataIndx: "invoiced_qty",
|
||||||
style: { backgroundColor: '#d4edda', textAlign: 'right' }
|
dataType: "float",
|
||||||
|
filter: true,
|
||||||
|
sortable: true,
|
||||||
|
align: "right",
|
||||||
|
render: (ui) => this.formatInteger(ui.cellData),
|
||||||
|
|
||||||
|
summary: {
|
||||||
|
type: "sum",
|
||||||
|
label: "Total:",
|
||||||
|
render: (ui) => this.formatInteger(ui.data)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Kgs",
|
||||||
|
width: 90,
|
||||||
|
dataIndx: "invoiced_qty_kg",
|
||||||
|
dataType: "float",
|
||||||
|
filter: true,
|
||||||
|
sortable: true,
|
||||||
|
align: "right",
|
||||||
|
render: (ui) => this.formatFloat(ui.cellData),
|
||||||
|
|
||||||
|
summary: {
|
||||||
|
type: "sum",
|
||||||
|
label: "Total:",
|
||||||
|
render: (ui) => this.formatFloat(ui.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Balance Qty",
|
title: "Balance Qty",
|
||||||
width: 60,
|
width: 90,
|
||||||
dataIndx: "balance_qty",
|
dataIndx: "balance_qty",
|
||||||
dataType: "float",
|
dataType: "float",
|
||||||
align: "right",
|
align: "right",
|
||||||
render: (ui) => this.formatInteger(ui.cellData),
|
render: (ui) => this.formatInteger(ui.cellData),
|
||||||
style: (ui) => {
|
summary: {
|
||||||
const balance = parseFloat(ui.cellData) || 0;
|
type: "sum",
|
||||||
return {
|
label: "Total:",
|
||||||
backgroundColor: balance > 0 ? '#f8d7da' : '#d4edda',
|
render: (ui) => this.formatInteger(ui.data)
|
||||||
textAlign: 'right'
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Status",
|
title: "Status",
|
||||||
width: 70,
|
width: 70,
|
||||||
|
summary: false,
|
||||||
dataIndx: "dispatch_status",
|
dataIndx: "dispatch_status",
|
||||||
dataType: "string",
|
dataType: "string",
|
||||||
align: "center",
|
align: "center",
|
||||||
render: (ui) => {
|
render: (ui) => {
|
||||||
const status = ui.cellData;
|
const status = ui.cellData || ''; // Default to empty string if undefined
|
||||||
|
if (!status) return ''; // Return empty if no status
|
||||||
|
|
||||||
const color = status === 'Full' ? '#155724' : '#856404';
|
const color = status === 'Full' ? '#155724' : '#856404';
|
||||||
return `<span style="color: ${color}; font-weight: bold;">${status}</span>`;
|
return `<span style="color: ${color}; font-weight: bold;">${status}</span>`;
|
||||||
},
|
},
|
||||||
style: (ui) => ({
|
attr:ui => ({
|
||||||
backgroundColor: ui.cellData === 'Full' ? '#d4edda' : '#fff3cd',
|
style: {
|
||||||
textAlign: 'center'
|
backgroundColor: ui.cellData > 0 ? '#d4edda' : '',
|
||||||
})
|
textAlign: 'right'
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
@ -868,7 +1079,8 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
dataType: "string",
|
dataType: "string",
|
||||||
align: "left",
|
align: "left",
|
||||||
frozen: true,
|
frozen: true,
|
||||||
style: { backgroundColor: '#f0f8ff', fontWeight: 'bold' }
|
style: { backgroundColor: '#f0f8ff', fontWeight: 'bold' },
|
||||||
|
filter: { type: 'textbox', condition: 'contain', listeners: ['keyup'] }
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -909,7 +1121,7 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
width: 60,
|
width: 60,
|
||||||
dataIndx: "uom_name",
|
dataIndx: "uom_name",
|
||||||
dataType: "string",
|
dataType: "string",
|
||||||
align: "center",
|
align: "left",
|
||||||
style: { textAlign: 'center' }
|
style: { textAlign: 'center' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1096,7 +1308,8 @@ export class CustomerOrderStatusGrid extends Component {
|
||||||
return 'badge-danger';
|
return 'badge-danger';
|
||||||
}
|
}
|
||||||
|
|
||||||
exportGrid(type) {
|
async exportGrid(type) {
|
||||||
|
|
||||||
let gridRef;
|
let gridRef;
|
||||||
let filename;
|
let filename;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,23 @@
|
||||||
<div class="header-card">
|
<div class="header-card">
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
<h5 class="header-title">Customer Order Status Dashboard</h5>
|
<h5 class="header-title">Customer Order Status Dashboard</h5>
|
||||||
<div class="header-stats" t-if="!state.isLoading">
|
<!-- Simple Month/Year Filter - Auto filter on change -->
|
||||||
|
<div class="simple-filter" t-if="!state.isLoading">
|
||||||
|
<div class="row g-2 align-items-center">
|
||||||
|
<div class="col-auto ms-auto">
|
||||||
|
<div class="input-group input-group-sm">
|
||||||
|
<span class="input-group-text">
|
||||||
|
<i class="fa fa-calendar"></i>
|
||||||
|
</span>
|
||||||
|
<input type="month"
|
||||||
|
class="form-control form-control-sm"
|
||||||
|
t-model="state.selectedMonthYear"
|
||||||
|
t-on-change="loadAllData"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="header-stats" t-if="!state.isLoading">
|
||||||
<div class="stats-container">
|
<div class="stats-container">
|
||||||
<div class="stat-item">
|
<div class="stat-item">
|
||||||
<span class="stat-label">Total Orders:</span>
|
<span class="stat-label">Total Orders:</span>
|
||||||
|
|
@ -366,7 +382,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-card {
|
.header-card {
|
||||||
background: linear-gradient(135deg, #fb4d2f 0%, #f494a9 100%);
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
|
||||||
|
|
@ -422,6 +438,7 @@
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
min-width: 60px;
|
min-width: 60px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
color : white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.refresh-btn {
|
.refresh-btn {
|
||||||
|
|
@ -744,33 +761,77 @@
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Simple Filter Styles - Right side */
|
||||||
|
.simple-filter {
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Position filter on right side */
|
||||||
|
.col-auto.ms-auto {
|
||||||
|
margin-left: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group-sm {
|
||||||
|
width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group-sm .form-control {
|
||||||
|
background: white;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
color: #495057;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group-sm .input-group-text {
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover effects */
|
||||||
|
.input-group-sm:hover .input-group-text {
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.col-auto.ms-auto {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.simple-filter {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ParamQuery Grid Customization */
|
/* ParamQuery Grid Customization */
|
||||||
.pq-grid {
|
<!-- .pq-grid {-->
|
||||||
border: none !important;
|
<!-- border: none !important;-->
|
||||||
}
|
<!-- }-->
|
||||||
|
|
||||||
.pq-grid .pq-grid-header {
|
<!-- .pq-grid .pq-grid-header {-->
|
||||||
background: #f8f9fa !important;
|
<!-- background: #f8f9fa !important;-->
|
||||||
border-bottom: 2px solid #dee2e6 !important;
|
<!-- border-bottom: 2px solid #dee2e6 !important;-->
|
||||||
}
|
<!-- }-->
|
||||||
|
|
||||||
.pq-grid .pq-grid-title {
|
<!-- .pq-grid .pq-grid-title {-->
|
||||||
color: #495057 !important;
|
<!-- color: #495057 !important;-->
|
||||||
font-weight: 600 !important;
|
<!-- font-weight: 600 !important;-->
|
||||||
}
|
<!-- }-->
|
||||||
|
|
||||||
.pq-grid .pq-grid-cell {
|
<!-- .pq-grid .pq-grid-cell {-->
|
||||||
border-right: 1px solid #e9ecef !important;
|
<!-- border-right: 1px solid #e9ecef !important;-->
|
||||||
border-bottom: 1px solid #e9ecef !important;
|
<!-- border-bottom: 1px solid #e9ecef !important;-->
|
||||||
}
|
<!-- }-->
|
||||||
|
|
||||||
.pq-grid .pq-grid-row:nth-child(even) {
|
<!-- .pq-grid .pq-grid-row:nth-child(even) {-->
|
||||||
background-color: #f8f9fa !important;
|
<!-- background-color: #f8f9fa !important;-->
|
||||||
}
|
<!-- }-->
|
||||||
|
|
||||||
.pq-grid .pq-grid-row:hover {
|
<!-- .pq-grid .pq-grid-row:hover {-->
|
||||||
background-color: #e9ecef !important;
|
<!-- background-color: #e9ecef !important;-->
|
||||||
}
|
<!-- }-->
|
||||||
</style>
|
</style>
|
||||||
</t>
|
</t>
|
||||||
</templates>
|
</templates>
|
||||||
Loading…
Reference in New Issue