new dashboards views
This commit is contained in:
parent
aa1fd0c881
commit
ccb7abe76a
|
|
@ -140,6 +140,12 @@ class SamashtiDashboard(models.AbstractModel):
|
|||
else:
|
||||
return []
|
||||
|
||||
@api.model
|
||||
def get_products_data(self):
|
||||
all_prod = self.env['product.product'].search([('type', '=', 'consu')])
|
||||
all_category = all_prod.category_id
|
||||
|
||||
|
||||
@api.model
|
||||
def get_sale_margin_data(self, from_date, to_date):
|
||||
# Get user's timezone
|
||||
|
|
|
|||
|
|
@ -4,6 +4,18 @@ import { useService } from "@web/core/utils/hooks";
|
|||
import { registry } from "@web/core/registry";
|
||||
import { standardActionServiceProps } from "@web/webclient/actions/action_service";
|
||||
|
||||
function formatFloat(value) {
|
||||
if (value === null || value === undefined || isNaN(value)) {
|
||||
return "0.00";
|
||||
}
|
||||
return parseFloat(value).toLocaleString('en-US', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class ConsumptionDashboard extends Component {
|
||||
static props = {
|
||||
...standardActionServiceProps,
|
||||
|
|
@ -102,7 +114,7 @@ export class ConsumptionDashboard extends Component {
|
|||
}
|
||||
// Check for 'Outer bag' in product name (case insensitive)
|
||||
if (row.product_name && row.product_name.toLowerCase().includes('outer bag')) {
|
||||
return 'Outer bag';
|
||||
return 'Outer Bags';
|
||||
}
|
||||
// Default to first 2 characters of product code
|
||||
if (row.product_code && row.product_code.length >= 2) {
|
||||
|
|
@ -170,12 +182,12 @@ export class ConsumptionDashboard extends Component {
|
|||
width: 120,
|
||||
filter: { type: 'textbox', condition: 'contain', listeners: ['keyup'] }
|
||||
},
|
||||
{ title: "Date", dataIndx: "date", width: 150 },
|
||||
{ title: "Date", dataIndx: "date", width: 100 },
|
||||
|
||||
{
|
||||
title: "Product Name",
|
||||
dataIndx: "product_name",
|
||||
width: 250,
|
||||
width: 300,
|
||||
filter: { type: 'textbox', condition: 'contain', listeners: ['keyup'] }
|
||||
},
|
||||
{
|
||||
|
|
@ -205,7 +217,7 @@ export class ConsumptionDashboard extends Component {
|
|||
width: 80
|
||||
},
|
||||
{
|
||||
title: "Value",
|
||||
title: "Value (INR)",
|
||||
dataIndx: "value",
|
||||
width: 120,
|
||||
dataType: "float",
|
||||
|
|
@ -218,7 +230,7 @@ export class ConsumptionDashboard extends Component {
|
|||
const getColumnPriority = (prefix) => {
|
||||
const priorityMap = {
|
||||
'Laminate': 1,
|
||||
'Outer bag': 2,
|
||||
'Outer Bags': 2,
|
||||
'RM':3,
|
||||
'PM':4,
|
||||
'ST':5,
|
||||
|
|
@ -250,19 +262,22 @@ export class ConsumptionDashboard extends Component {
|
|||
// Create dynamic columns
|
||||
const dynamicColumns = sortedPrefixes.map(prefix => ({
|
||||
dataIndx: prefix,
|
||||
title: prefix+" ₹" ,
|
||||
title: (() => {
|
||||
let label;
|
||||
|
||||
if (prefix === 'FU') label = 'Fuel';
|
||||
else if (prefix === 'MA') label = 'Maintenance';
|
||||
else if (prefix === 'MP') label = 'Manpower';
|
||||
else if (prefix === 'PW') label = 'Power';
|
||||
else label = prefix;
|
||||
|
||||
return label + " (INR)";
|
||||
})(),
|
||||
width: 120,
|
||||
align: "right",
|
||||
dataType: "float",
|
||||
format: "#,###.00",
|
||||
summary: { type: "sum" },
|
||||
render: function(ui) {
|
||||
const value = ui.cellData;
|
||||
// if (value > 0) {
|
||||
// return `<span >${value}</span>`;
|
||||
// }
|
||||
return value ? value.toFixed(2) : "0";
|
||||
}
|
||||
}));
|
||||
|
||||
return [...baseColumns, ...dynamicColumns];
|
||||
|
|
|
|||
|
|
@ -4,6 +4,15 @@ import { useService } from "@web/core/utils/hooks";
|
|||
import { registry } from "@web/core/registry";
|
||||
import { standardActionServiceProps } from "@web/webclient/actions/action_service";
|
||||
|
||||
function formatFloat(value) {
|
||||
if (value === null || value === undefined || isNaN(value)) {
|
||||
return "0.00";
|
||||
}
|
||||
return parseFloat(value).toLocaleString('en-US', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export class SaleDashboard extends Component {
|
||||
|
|
@ -49,6 +58,27 @@ export class SaleDashboard extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
getTotalProductionValue() {
|
||||
return formatFloat(this.state.sale_rows.reduce((sum, row) => sum + (row.cost || 0), 0).toFixed(2)) + " ₹";
|
||||
}
|
||||
getTotalSaleValue() {
|
||||
return formatFloat(this.state.sale_rows.reduce((sum, row) => sum + (row.sale_price || 0), 0).toFixed(2)) + " ₹";
|
||||
}
|
||||
getTotalMarginValue() {
|
||||
return formatFloat(this.state.sale_rows.reduce((sum, row) => sum + (row.margin || 0), 0).toFixed(2)) + " ₹";
|
||||
}
|
||||
getMarginPercentage() {
|
||||
const totalMarginValue = this.state.sale_rows.reduce((sum, row) => sum + (row.margin || 0), 0).toFixed(2)
|
||||
const totalSaleValue = this.state.sale_rows.reduce((sum, row) => sum + (row.sale_price || 0), 0).toFixed(2)
|
||||
|
||||
if (totalSaleValue === 0) return 0;
|
||||
|
||||
const percentage = (totalMarginValue / totalSaleValue) * 100;
|
||||
return formatFloat(percentage.toFixed(2)); // Returns with 2 decimal places
|
||||
}
|
||||
|
||||
|
||||
|
||||
initializeDates() {
|
||||
const today = new Date();
|
||||
const firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
|
|
@ -103,12 +133,12 @@ export class SaleDashboard extends Component {
|
|||
{ title: "Invoice", dataIndx: "invoice", width: 180, filter: { type: 'textbox', condition: 'contain', listeners: ['keyup'] } },
|
||||
{ title: "Customer", dataIndx: "customer", width: 280, filter: { type: 'textbox', condition: 'contain', listeners: ['keyup'] } },
|
||||
{ title: "Tags", dataIndx: "tags", width: 100, },
|
||||
{ title: "Quantity (Bags/No's)", dataIndx: "quantity", width: 150, dataType: "float", format: "#,###.00", summary: { type: "sum" }, align: "right" },
|
||||
{ title: "Quantity (Bags/No's)", dataIndx: "quantity", width: 150, dataType: "float", format: "#,###.00", summary: { type: "sum_" }, align: "right" },
|
||||
{ title: "Weight (kgs)", dataIndx: "weight", width: 120 },
|
||||
{ title: "Production Cost (INR)", dataIndx: "cost", width: 150, dataType: "float", format: "#,###.00", summary: { type: "sum" }, align: "right" },
|
||||
{ title: "Sale Price (INR)", dataIndx: "sale_price", width: 120, dataType: "float", format: "#,###.00", summary: { type: "sum" }, align: "right" },
|
||||
{ title: "Margin (INR)", dataIndx: "margin", width: 120, dataType: "float", format: "#,###.00", summary: { type: "sum" }, align: "right" },
|
||||
{ title: "Margin %", dataIndx: "margin_percent", width: 120, dataType: "float", format: "#,###.00", summary: { type: "sum" }, align: "right" },
|
||||
{ title: "Production Cost (INR)", dataIndx: "cost", width: 150, dataType: "float", format: "#,###.00", summary: { type: "sum_" }, align: "right" },
|
||||
{ title: "Sale Price (INR)", dataIndx: "sale_price", width: 120, dataType: "float", format: "#,###.00", summary: { type: "sum_" }, align: "right" },
|
||||
{ title: "Margin (INR)", dataIndx: "margin", width: 120, dataType: "float", format: "#,###.00", summary: { type: "sum_" }, align: "right" },
|
||||
{ title: "Margin %", dataIndx: "margin_percent", width: 120, dataType: "float", format: "#,###.00", summary: { type: "sum_" }, align: "right" },
|
||||
{
|
||||
title: "View",
|
||||
width: 120,
|
||||
|
|
@ -135,6 +165,10 @@ export class SaleDashboard extends Component {
|
|||
async renderSaleGrid() {
|
||||
const columns = await this.getSaleColumns()
|
||||
const agg = pq.aggregate;
|
||||
agg.sum_ = function(arr, col) {
|
||||
return " " + agg.sum(arr, col).toFixed(2).toString();
|
||||
};
|
||||
|
||||
|
||||
const gridOptions = {
|
||||
selectionModel: { type: "row" },
|
||||
|
|
|
|||
|
|
@ -3,60 +3,120 @@
|
|||
<t t-name="SaleDashboard" owl="1">
|
||||
<div class="p-4" style="height: 100%; overflow-y: auto;">
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<!-- Left Side: Title with Icon -->
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="bg-success rounded-circle p-2 me-3">
|
||||
<i class="fa fa-chart-line text-white"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-success fw-bold mb-1">Sale Margin Dashboard</h4>
|
||||
<p class="text-muted mb-0 small">
|
||||
<i class="fa fa-calendar me-1"></i>
|
||||
<span t-esc="state.saleFromDate || 'Start Date'"/>
|
||||
<i class="fa fa-arrow-right mx-2"></i>
|
||||
<span t-esc="state.saleToDate || 'End Date'"/>
|
||||
</p>
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<!-- Left Side: Title with Icon -->
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="bg-success rounded-circle p-2 me-3">
|
||||
<i class="fa fa-chart-line text-white"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-success fw-bold mb-1">Sale Margin Dashboard</h4>
|
||||
<p class="text-muted mb-0 small">
|
||||
<i class="fa fa-calendar me-1"></i>
|
||||
<span t-esc="state.saleFromDate || 'Start Date'"/>
|
||||
<i class="fa fa-arrow-right mx-2"></i>
|
||||
<span t-esc="state.saleToDate || 'End Date'"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Side: Date Controls -->
|
||||
<div class="col-md-6">
|
||||
<div class="row g-2 align-items-center justify-content-end">
|
||||
<div class="col-auto">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</span>
|
||||
<input type="text" id="saleFromDate" t-model="state.saleFromDate"
|
||||
class="form-control form-control-sm" placeholder="From Date"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</span>
|
||||
<input type="text" id="saleToDate" t-model="state.saleToDate"
|
||||
class="form-control form-control-sm" placeholder="To Date"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<button type="button" class="btn btn-success btn-sm" t-on-click="loadSaleData">
|
||||
<i class="fa fa-refresh me-1"></i> Update
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Side: Date Controls -->
|
||||
<div class="col-md-6">
|
||||
<div class="row g-2 align-items-center justify-content-end">
|
||||
<div class="col-auto">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</span>
|
||||
<input type="text" id="saleFromDate" t-model="state.saleFromDate"
|
||||
class="form-control form-control-sm" placeholder="From Date"/>
|
||||
<div class="row mb-4">
|
||||
<div class="col mb-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center py-4">
|
||||
<div class="text-primary mb-3">
|
||||
<i class="fas fa-receipt fa-2x"></i>
|
||||
</div>
|
||||
<h6 class="card-title text-muted small mb-2">Total Invoices</h6>
|
||||
<h4 class="text-primary fw-bold mb-0" t-esc="state.sale_rows.length"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</span>
|
||||
<input type="text" id="saleToDate" t-model="state.saleToDate"
|
||||
class="form-control form-control-sm" placeholder="To Date"/>
|
||||
<div class="col mb-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center py-4">
|
||||
<div class="text-danger mb-3">
|
||||
<i class="fas fa-industry fa-2x"></i>
|
||||
</div>
|
||||
<h6 class="card-title text-muted small mb-2">Total Production</h6>
|
||||
<h4 class="text-danger fw-bold mb-0" t-esc="this.getTotalProductionValue()"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<button type="button" class="btn btn-success btn-sm" t-on-click="loadSaleData">
|
||||
<i class="fa fa-refresh me-1"></i> Update
|
||||
</button>
|
||||
<div class="col mb-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center py-4">
|
||||
<div class="text-warning mb-3">
|
||||
<i class="fas fa-shopping-cart fa-2x"></i>
|
||||
</div>
|
||||
<h6 class="card-title text-muted small mb-2">Total Sale</h6>
|
||||
<h4 class="text-warning fw-bold mb-0" t-esc="this.getTotalSaleValue()"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col mb-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center py-4">
|
||||
<div class="text-success mb-3">
|
||||
<i class="fas fa-chart-line fa-2x"></i>
|
||||
</div>
|
||||
<h6 class="card-title text-muted small mb-2">Total Margin</h6>
|
||||
<h4 class="text-success fw-bold mb-0" t-esc="this.getTotalMarginValue()"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col mb-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center py-4">
|
||||
<div class="text-info mb-3">
|
||||
<i class="fas fa-percentage fa-2x"></i>
|
||||
</div>
|
||||
<h6 class="card-title text-muted small mb-2">Margin %</h6>
|
||||
<h4 class="text-info fw-bold mb-0" t-esc="this.getMarginPercentage() + '%'"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0">
|
||||
|
|
|
|||
|
|
@ -4,6 +4,17 @@ import { useService } from "@web/core/utils/hooks";
|
|||
import { registry } from "@web/core/registry";
|
||||
import { standardActionServiceProps } from "@web/webclient/actions/action_service";
|
||||
|
||||
function formatFloat(value) {
|
||||
if (value === null || value === undefined || isNaN(value)) {
|
||||
return "0.00";
|
||||
}
|
||||
return parseFloat(value).toLocaleString('en-US', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export class StockDashboard extends Component {
|
||||
static props = {
|
||||
...standardActionServiceProps,
|
||||
|
|
@ -17,6 +28,7 @@ export class StockDashboard extends Component {
|
|||
|
||||
this.state = useState({
|
||||
rows: [],
|
||||
category:[],
|
||||
fromDate: "",
|
||||
toDate: ""
|
||||
});
|
||||
|
|
@ -92,7 +104,71 @@ export class StockDashboard extends Component {
|
|||
console.error("Error loading data:", error);
|
||||
}
|
||||
}
|
||||
getTotalStockValue() {
|
||||
return formatFloat(this.state.rows.reduce((sum, row) => sum + (row.value || 0), 0).toFixed(2)) + " ₹";
|
||||
}
|
||||
parseFloatValue(value) {
|
||||
if (value === null || value === undefined || value === "") {
|
||||
return 0;
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
let cleaned = value.replace(/[^\d.-]/g, '');
|
||||
let result = parseFloat(cleaned);
|
||||
return isNaN(result) ? 0 : result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Stock dashboard calculation methods
|
||||
getTotalProductsCount() {
|
||||
// Count unique products based on product_code
|
||||
const uniqueProducts = new Set(
|
||||
this.state.rows
|
||||
.filter(row => row.product_code)
|
||||
.map(row => row.product_code)
|
||||
);
|
||||
return uniqueProducts.size;
|
||||
}
|
||||
|
||||
getCategoryCount() {
|
||||
// Count unique categories
|
||||
const uniqueCategories = new Set(
|
||||
this.state.rows
|
||||
.filter(row => row.category)
|
||||
.map(row => row.category)
|
||||
);
|
||||
return uniqueCategories.size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
getOutOfStockCount() {
|
||||
return this.state.rows.filter(row => {
|
||||
const currentStock = this.parseFloatValue(row.closing_stock || row.quantity || 0);
|
||||
return currentStock <= 0;
|
||||
}).length;
|
||||
}
|
||||
|
||||
getLowStockCount() {
|
||||
return this.state.rows.filter(row => {
|
||||
const currentStock = this.parseFloatValue(row.closing_stock || row.quantity || 0);
|
||||
const minStock = this.parseFloatValue(row.min_stock) || 50; // Default minimum stock
|
||||
return currentStock > 0 && currentStock < minStock;
|
||||
}).length;
|
||||
}
|
||||
|
||||
getLowStockPercentage() {
|
||||
const totalProducts = this.getTotalProductsCount();
|
||||
const lowStockCount = this.getLowStockCount();
|
||||
|
||||
if (totalProducts === 0) return "0.00";
|
||||
|
||||
const percentage = (lowStockCount / totalProducts) * 100;
|
||||
return formatFloat(percentage);
|
||||
}
|
||||
async getColumns() {
|
||||
return [
|
||||
{ title: "Product Code", dataIndx: "product_code", width: 100, filter: { type: 'textbox', condition: 'contain', listeners: ['keyup'] } },
|
||||
|
|
@ -118,8 +194,13 @@ export class StockDashboard extends Component {
|
|||
width: "100%",
|
||||
height: "100%",
|
||||
editable: false,
|
||||
freezeCols: 2,
|
||||
stripeRows: true,
|
||||
filterModel: { on: true, mode: "AND", header: true, autoSearch: true, type: 'local', minLength: 1 },
|
||||
menuIcon: true, //show header menu icon initially.
|
||||
menuUI: {
|
||||
tabs: ['filter'] //display only filter tab.
|
||||
},
|
||||
filterModel: { on: true, mode: "AND", header: true, autoSearch: true, type: 'local', minLength: 1,menuIcon: true },
|
||||
dataModel: { data: this.state.rows, location: "local", sorting: "local", paging: "local" },
|
||||
colModel: columns,
|
||||
toolbar: {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<t t-name="StockDashboard" owl="1">
|
||||
<div class="p-4" style="height: 100%; overflow-y: auto;">
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<!-- Left Side: Title with Icon -->
|
||||
<div class="col-md-6">
|
||||
|
|
@ -55,7 +55,67 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<!-- Total Products Card -->
|
||||
<div class="col mb-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center py-4">
|
||||
<div class="text-primary mb-3">
|
||||
<i class="fas fa-cubes fa-2x"></i>
|
||||
</div>
|
||||
<h6 class="card-title text-muted small mb-2">Total Products</h6>
|
||||
<h4 class="text-primary fw-bold mb-0">
|
||||
<span t-esc="this.getTotalProductsCount()"/>
|
||||
</h4>
|
||||
<small class="text-muted" t-esc="'Across ' + this.getCategoryCount() + ' categories'"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Current Stock Value Card -->
|
||||
<div class="col mb-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center py-4">
|
||||
<div class="text-success mb-3">
|
||||
<i class="fas fa-dollar-sign fa-2x"></i>
|
||||
</div>
|
||||
<h6 class="card-title text-muted small mb-2">Current Stock Value</h6>
|
||||
<h4 class="text-success fw-bold mb-0" t-esc="this.getTotalStockValue()"/>
|
||||
<small class="text-muted">Total inventory value</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Out of Stock Products Card -->
|
||||
<div class="col mb-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center py-4">
|
||||
<div class="text-danger mb-3">
|
||||
<i class="fas fa-times-circle fa-2x"></i>
|
||||
</div>
|
||||
<h6 class="card-title text-muted small mb-2">Out of Stock</h6>
|
||||
<h4 class="text-danger fw-bold mb-0" t-esc="this.getOutOfStockCount()"/>
|
||||
<small class="text-muted">Products need restocking</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Low Stock Percentage Card -->
|
||||
<div class="col mb-4">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center py-4">
|
||||
<div class="text-info mb-3">
|
||||
<i class="fas fa-exclamation-triangle fa-2x"></i>
|
||||
</div>
|
||||
<h6 class="card-title text-muted small mb-2">Low Stock Alert</h6>
|
||||
<h4 class="text-info fw-bold mb-0" t-esc="this.getLowStockCount()"/>
|
||||
<small class="text-muted">Below minimum levels</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-primary text-white">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<menuitem id="samashti_dashboard_root"
|
||||
name="Overview"
|
||||
action="stock_dashboard_action"
|
||||
sequence="-100" groups="dashboard.group_proforma_sales_dashboard"/>
|
||||
|
||||
<!-- Stock Dashboard -->
|
||||
<record id="stock_dashboard_action" model="ir.actions.client">
|
||||
<field name="name">Stock Dashboard</field>
|
||||
|
|
@ -11,12 +8,10 @@
|
|||
<field name="context">{'user_id':uid}</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="stock_dashboard_menu"
|
||||
name="Stock Dashboard"
|
||||
action="stock_dashboard_action"
|
||||
sequence="10"
|
||||
parent="samashti_dashboard_root"
|
||||
groups="dashboard.group_proforma_sales_dashboard"/>
|
||||
<record id="consumption_dashboard_action" model="ir.actions.client">
|
||||
<field name="name">Consumption Dashboard</field>
|
||||
<field name="tag">ConsumptionDashboard</field>
|
||||
</record>
|
||||
|
||||
<record id="sale_dashboard_action" model="ir.actions.client">
|
||||
<field name="name">Sale Margin Dashboard</field>
|
||||
|
|
@ -24,6 +19,19 @@
|
|||
<field name="context">{'user_id':uid}</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="samashti_dashboard_root"
|
||||
name="Overview"
|
||||
action="stock_dashboard_action"
|
||||
sequence="-100" groups="dashboard.group_proforma_sales_dashboard"/>
|
||||
|
||||
<menuitem id="stock_dashboard_menu"
|
||||
name="Stock Dashboard"
|
||||
action="stock_dashboard_action"
|
||||
sequence="10"
|
||||
parent="samashti_dashboard_root"
|
||||
groups="dashboard.group_proforma_sales_dashboard"/>
|
||||
|
||||
|
||||
<menuitem id="sale_dashboard_menu"
|
||||
name="Sale Margin Report"
|
||||
action="sale_dashboard_action"
|
||||
|
|
@ -31,10 +39,7 @@
|
|||
parent="samashti_dashboard_root"
|
||||
groups="dashboard.group_proforma_sales_dashboard"/>
|
||||
|
||||
<record id="consumption_dashboard_action" model="ir.actions.client">
|
||||
<field name="name">Consumption Dashboard</field>
|
||||
<field name="tag">ConsumptionDashboard</field>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem id="consumption_dashboard_menu"
|
||||
name="Consumption Report"
|
||||
|
|
|
|||
Loading…
Reference in New Issue