221 lines
10 KiB
Python
221 lines
10 KiB
Python
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: includes inventory adjustments before fromDate
|
|
COALESCE(SUM(CASE
|
|
WHEN sm.date < {fromDate} AND sl_dest.usage = 'internal' THEN sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
WHEN sm.date < {fromDate} AND sl_src.usage = 'internal' THEN -sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
WHEN sm.date < {fromDate} AND (sl_src.usage = 'inventory' OR sl_dest.usage = 'inventory') THEN sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
ELSE 0
|
|
END), 0) AS opening_stock,
|
|
|
|
-- Receipts: from supplier and inventory adjustments in date range
|
|
COALESCE(SUM(CASE
|
|
WHEN sm.date BETWEEN {fromDate} AND {toDate}
|
|
AND sl_dest.usage = 'internal'
|
|
AND sl_src.usage in ('supplier','inventory') THEN sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
WHEN sm.date BETWEEN {fromDate} AND {toDate} AND (sl_src.usage = 'inventory' OR sl_dest.usage = 'inventory') THEN sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
ELSE 0
|
|
END), 0) AS receipts,
|
|
|
|
-- Production: internal moves 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 * (uom.factor /sm_uom.factor)
|
|
ELSE 0
|
|
END), 0) AS production,
|
|
|
|
-- Consumption: internal moves to production
|
|
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 * (uom.factor /sm_uom.factor)
|
|
ELSE 0
|
|
END), 0) AS consumption,
|
|
|
|
-- Dispatch: internal moves to customer
|
|
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 * (uom.factor /sm_uom.factor)
|
|
ELSE 0
|
|
END), 0) AS dispatch,
|
|
|
|
-- Closing Stock = Opening + Receipts + Production - Consumption - Dispatch + Inventory adjustments
|
|
(
|
|
COALESCE(SUM(CASE
|
|
WHEN sm.date < {fromDate} AND sl_dest.usage = 'internal' THEN sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
WHEN sm.date < {fromDate} AND sl_src.usage = 'internal' THEN -sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
WHEN sm.date < {fromDate} AND (sl_src.usage = 'inventory' OR sl_dest.usage = 'inventory') THEN sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
WHEN sm.date BETWEEN {fromDate} AND {toDate} AND sl_dest.usage = 'internal' AND sl_src.usage IN ('supplier', 'production') THEN sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
WHEN sm.date BETWEEN {fromDate} AND {toDate} AND (sl_src.usage = 'inventory' OR sl_dest.usage = 'inventory') THEN sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
WHEN sm.date BETWEEN {fromDate} AND {toDate} AND sl_src.usage = 'internal' AND sl_dest.usage = 'production' THEN -sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
WHEN sm.date BETWEEN {fromDate} AND {toDate} AND sl_src.usage = 'internal' AND sl_dest.usage = 'customer' THEN -sm.product_uom_qty * (uom.factor /sm_uom.factor)
|
|
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 -- Product default UOM
|
|
JOIN
|
|
uom_uom sm_uom ON sm.product_uom = sm_uom.id -- Stock move UOM
|
|
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', 'inventory') AND
|
|
sl_dest.usage IN ('internal', 'supplier', 'production', 'customer', 'inventory') AND
|
|
sm.state = 'done' AND
|
|
pt.type = 'consu'
|
|
|
|
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 '-'
|
|
row['value'] = row['closing_stock'] * row['current_cost']
|
|
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'],
|
|
'id':r['id'],
|
|
'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
|
|
|
|
def action_view_sale_orders(self, id):
|
|
result = self.env['ir.actions.act_window']._for_xml_id('sale.action_orders')
|
|
result['views'] = [(self.env.ref('sale.view_order_form', False).id, 'form')]
|
|
result['res_id'] = id
|
|
result['target'] = 'self',
|
|
return result
|
|
|
|
|
|
|