from odoo import models, fields, api, _ from odoo.exceptions import UserError, ValidationError from collections import defaultdict from functools import reduce from datetime import datetime, time class SamashtiDashboard(models.AbstractModel): _name = 'samashti.board' _description = "Samashti Dashboard" @api.model def get_stock_moves_data(self, from_date,to_date): fromDate = "'"+str(from_date)+" 00:00:00'" toDate = "'"+str(to_date)+" 23:59:59'" sql = f""" SELECT pp.default_code AS product_code, pt.name AS product_name, pc.name AS category, uom.name AS uom, -- Opening Stock COALESCE(SUM(CASE WHEN sm.date < {fromDate} AND sl_dest.usage = 'internal' THEN sm.product_uom_qty WHEN sm.date < {fromDate} AND sl_src.usage = 'internal' THEN -sm.product_uom_qty ELSE 0 END), 0) AS opening_stock, -- Receipts (to internal from supplier/purchase) COALESCE(SUM(CASE WHEN sm.date BETWEEN {fromDate} AND {toDate} AND sl_dest.usage = 'internal' AND sl_src.usage = 'supplier' THEN sm.product_uom_qty ELSE 0 END), 0) AS receipts, -- Production (to internal from Production) COALESCE(SUM(CASE WHEN sm.date BETWEEN {fromDate} AND {toDate} AND sl_dest.usage = 'internal' AND sl_src.usage = 'production' THEN sm.product_uom_qty ELSE 0 END), 0) AS production, -- Consumption (to production only) COALESCE(SUM(CASE WHEN sm.date BETWEEN {fromDate} AND {toDate} AND sl_src.usage = 'internal' AND sl_dest.usage = 'production' THEN sm.product_uom_qty ELSE 0 END), 0) AS consumption, -- Dispatch (to customer only) COALESCE(SUM(CASE WHEN sm.date BETWEEN {fromDate} AND {toDate} AND sl_src.usage = 'internal' AND sl_dest.usage = 'customer' THEN sm.product_uom_qty ELSE 0 END), 0) AS dispatch, -- Closing Stock = Opening + Receipts + Production - Consumption - Dispatch ( COALESCE(SUM(CASE WHEN sm.date < {fromDate} AND sl_dest.usage = 'internal' THEN sm.product_uom_qty WHEN sm.date < {fromDate} AND sl_src.usage = 'internal' THEN -sm.product_uom_qty WHEN sm.date BETWEEN {fromDate} AND {toDate} AND sl_dest.usage = 'internal' AND sl_src.usage IN ('supplier', 'production') THEN sm.product_uom_qty WHEN sm.date BETWEEN {fromDate} AND {toDate} AND sl_src.usage = 'internal' AND sl_dest.usage = 'production' THEN -sm.product_uom_qty WHEN sm.date BETWEEN {fromDate} AND {toDate} AND sl_src.usage = 'internal' AND sl_dest.usage = 'customer' THEN -sm.product_uom_qty ELSE 0 END), 0) ) AS closing_stock FROM stock_move sm JOIN product_product pp ON sm.product_id = pp.id JOIN product_template pt ON pp.product_tmpl_id = pt.id JOIN product_category pc ON pt.categ_id = pc.id JOIN uom_uom uom ON pt.uom_id = uom.id JOIN stock_location sl_src ON sm.location_id = sl_src.id JOIN stock_location sl_dest ON sm.location_dest_id = sl_dest.id WHERE sl_src.usage IN ('internal', 'supplier', 'production', 'customer') AND sl_dest.usage IN ('internal', 'supplier', 'production', 'customer') AND sm.state = 'done' AND pt.type = 'consu' AND sm.date BETWEEN {fromDate} AND {toDate} GROUP BY pp.default_code, pt.name, pc.name, uom.name ORDER BY pt.name; """ self.env.cr.execute(sql) data = self.env.cr.dictfetchall() if data: for row in data: row['product_name'] = '['+row['product_code']+'] '+ list(row['product_name'].values())[0] if row['product_name'] else '' row['uom'] = list(row['uom'].values())[0] if row['uom'] else '-' return data else: return [] @api.model def get_sale_margin_data(self,from_date,to_date): fromDate = "'"+str(from_date)+" 00:00:00'" toDate = "'"+str(to_date)+" 23:59:59'" datas = [] sale_orders = self.env['sale.order'].search_read( [ ('state', '=', 'sale'), ('date_order', '>=', fromDate), ('date_order', '<=', toDate) ], ['id', 'name', 'amount_total', 'partner_id', 'total_production_cost','date_order'] ) for r in sale_orders: cost = r['total_production_cost'] sale_price = r['amount_total'] margin = sale_price - cost margin_percent = (margin / sale_price * 100) if sale_price else 0.0 customer = r['partner_id'][-1] quantity = sum(self.env['sale.order'].browse(r['id']).order_line.mapped('product_uom_qty')) weight = str(sum(self.env['sale.order'].browse(r['id']).order_line.mapped('bag_weight')))+" kg" datas.append({ 'sale_order': r['name'], 'weight':weight, 'customer':customer, 'quantity':quantity, 'cost': cost, 'date':r['date_order'], 'sale_price': sale_price, 'margin': margin, 'margin_percent':margin_percent }) return datas where_caluse = f" AND so.date_order BETWEEN {fromDate} AND {toDate}" sql = """ SELECT so.name AS sale_order, COALESCE(pp.default_code, '') AS product_code, '[' || (COALESCE(pp.default_code, '') || '] ' || jsonb_extract_path_text(pt.name, rp.lang)) AS product_name, pc.complete_name AS category, sl.product_uom_qty AS quantity, COALESCE(sl.unit_prod_cost, 1) AS unit_cost, COALESCE(sl.price_unit, 1) AS unit_sale_price, ABS(COALESCE(sl.unit_prod_cost, 1) - COALESCE(sl.price_unit, 1)) AS margin, sl.product_uom_qty * COALESCE(sl.unit_prod_cost, 1) AS total_cost, sl.product_uom_qty * COALESCE(sl.price_unit, 1) AS total_sale_price, ABS((sl.product_uom_qty * COALESCE(sl.unit_prod_cost, 1)) - (sl.product_uom_qty * COALESCE(sl.price_unit, 1))) AS total_margin FROM sale_order_line sl JOIN sale_order so ON so.id = sl.order_id JOIN product_product pp ON pp.id = sl.product_id JOIN product_template pt ON pt.id = pp.product_tmpl_id LEFT JOIN product_category pc ON pc.id = pt.categ_id JOIN res_company rc ON rc.id = sl.company_id JOIN res_partner rp ON rp.id = rc.partner_id WHERE sl.state = 'sale' """ if where_caluse: sql += where_caluse self.env.cr.execute(sql) data = self.env.cr.dictfetchall() if data: return data else: return [] def _get_production_cost(self, sale_order_id): sale_order = self.env['sale.order'].browse(sale_order_id) cost = 0.0 for line in sale_order.order_line.filtered(lambda l: l.product_id.type == 'consu'): line_cost = line.purchase_price or 0 cost += line_cost * line.product_uom_qty for line in sale_order.order_line.filtered(lambda l: l.product_id.type == 'service' and l.price_total > 0): cost += line.price_total return cost