new update
This commit is contained in:
parent
07818afb3e
commit
57061ad060
|
|
@ -6,7 +6,7 @@
|
|||
'description': """ BOM Cost """,
|
||||
'author': 'Raman Marikanti',
|
||||
'category': 'Manufacturing',
|
||||
'depends': ['sale_management', 'mrp','stock'],
|
||||
'depends': ['sale_management', 'mrp','stock',],
|
||||
'data': [
|
||||
"views/bom_view.xml",
|
||||
"report/mrp_costing_report.xml",
|
||||
|
|
|
|||
|
|
@ -4,13 +4,98 @@ from odoo.tools import float_round
|
|||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
|
||||
class SaleOrderInherit(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
freight_charges = fields.Monetary(string='Freight', readonly=False)
|
||||
total_production_cost = fields.Monetary(string="Total Production Cost", readonly=True, compute="_compute_purchase_price", precompute=True)
|
||||
|
||||
@api.depends('freight_charges', 'order_line')
|
||||
def _compute_purchase_price(self):
|
||||
for order in self:
|
||||
production_cost = 0
|
||||
for line in order.order_line:
|
||||
production_cost += line.purchase_price * line.product_uom_qty
|
||||
order.total_production_cost = production_cost + order.freight_charges
|
||||
|
||||
|
||||
|
||||
#
|
||||
# class AccountMoveInherit(models.Model):
|
||||
# _inherit = 'account.move'
|
||||
#
|
||||
# freight_charges = fields.Monetary(string='Freight Charges', readonly=False, store=True,
|
||||
# compute='_compute_freight_charges_amount')
|
||||
#
|
||||
# @api.onchange('freight_charges')
|
||||
# @api.depends(
|
||||
# 'invoice_line_ids.currency_rate',
|
||||
# 'invoice_line_ids.tax_base_amount',
|
||||
# 'invoice_line_ids.tax_line_id',
|
||||
# 'invoice_line_ids.price_total',
|
||||
# 'invoice_line_ids.price_subtotal',
|
||||
# 'invoice_payment_term_id',
|
||||
# 'partner_id',
|
||||
# 'currency_id',
|
||||
# )
|
||||
# def _compute_tax_totals(self):
|
||||
# """ Computed field used for custom widget's rendering.
|
||||
# Only set on invoices.
|
||||
# """
|
||||
# res = super()._compute_tax_totals()
|
||||
# for order in self:
|
||||
# order.tax_totals['subtotals'][0]['base_amount'] += order.freight_charges
|
||||
# order.tax_totals['subtotals'][0]['base_amount_currency'] += order.freight_charges
|
||||
# order.tax_totals['base_amount'] += order.freight_charges
|
||||
# order.tax_totals['base_amount_currency'] += order.freight_charges
|
||||
# order.tax_totals['total_amount'] += order.freight_charges
|
||||
# order.tax_totals['total_amount_currency'] += order.freight_charges
|
||||
# return res
|
||||
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
_inherit = 'sale.order.line'
|
||||
|
||||
unit_prod_cost = fields.Float('Unit Prodcut Cost',digits="Product Unit of Measure")
|
||||
|
||||
@api.depends('product_id')
|
||||
def _compute_unit_prod_cost(self):
|
||||
purchase_price = fields.Float(
|
||||
string="Cost", compute="_compute_purchase_price",
|
||||
digits='Product Price', store=True, readonly=False, copy=False, precompute=True,
|
||||
groups="base.group_user")
|
||||
|
||||
bag_weight = fields.Float(
|
||||
string="Weight", compute="_compute_bag_weight",
|
||||
digits='Product Price', store=True, readonly=False, precompute=True,
|
||||
groups="base.group_user")
|
||||
|
||||
@api.depends('product_id', 'company_id', 'product_uom')
|
||||
def _compute_bag_weight(self):
|
||||
for line in self:
|
||||
line.unit_prod_cost = line.product_id.standard_price
|
||||
line.bag_weight = line.product_id.weight * line.product_uom_qty
|
||||
|
||||
|
||||
@api.depends('product_id', 'company_id', 'currency_id', 'product_uom')
|
||||
def _compute_purchase_price(self):
|
||||
for line in self:
|
||||
if not line.product_id:
|
||||
line.purchase_price = 0.0
|
||||
continue
|
||||
line = line.with_company(line.company_id)
|
||||
|
||||
# Convert the cost to the line UoM
|
||||
product_cost = line.product_id.uom_id._compute_price(
|
||||
line.product_id.standard_price,
|
||||
line.product_uom,
|
||||
)
|
||||
|
||||
line.purchase_price = line._convert_to_sol_currency(
|
||||
product_cost,
|
||||
line.product_id.cost_currency_id)
|
||||
|
||||
|
||||
|
||||
@api.depends('product_id', 'product_uom', 'product_uom_qty')
|
||||
def _compute_price_unit(self):
|
||||
for line in self:
|
||||
line.price_unit = 0.0
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,47 @@
|
|||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Inherit sale invoice Form View for freight_charges field addition -->
|
||||
<record id="sale_order_form_inherit" model="ir.ui.view">
|
||||
<field name="name">sale.order.form.inherit</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='order_line']/list//field[@name='price_unit']" position="after">
|
||||
<field name="purchase_price" groups="base.group_user"/>
|
||||
<field name="bag_weight" groups="base.group_user"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='tax_totals']" position="before">
|
||||
<div class="d-flex float-end" colspan="2" groups="base.group_user">
|
||||
<label for="freight_charges"/>
|
||||
<div>
|
||||
<field name="freight_charges" class="oe_inline" force_save="1" widget="monetary" options="{'currency_field': 'currency_id'}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex float-end" colspan="2" groups="base.group_user">
|
||||
<label for="total_production_cost"/>
|
||||
<div>
|
||||
<field name="total_production_cost" class="oe_inline" force_save="1" widget="monetary" options="{'currency_field': 'currency_id'}"/>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- <record id="account_move_form_inherit" model="ir.ui.view">-->
|
||||
<!-- <field name="name">account.move.form.inherit</field>-->
|
||||
<!-- <field name="model">account.move</field>-->
|
||||
<!-- <field name="inherit_id" ref="account.view_move_form"/>-->
|
||||
<!-- <field name="arch" type="xml">-->
|
||||
<!-- <xpath expr="//field[@name='tax_totals']" position="before">-->
|
||||
<!-- <field name="freight_charges" force_save="1" string="Freight" widget="monetary" options="{'currency_field': 'currency_id'}"/>-->
|
||||
<!-- </xpath>-->
|
||||
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
|
||||
|
||||
<record id="mrp_production_form_view_decoration" model="ir.ui.view">
|
||||
<field name="name">mrp.production.inherited.form.decoration</field>
|
||||
<field name="model">mrp.production</field>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
'name': 'Samashti Dashboard (OWL)',
|
||||
'version': '1.0',
|
||||
'category': 'View',
|
||||
'license': 'LGPL-3',
|
||||
'summary': 'Samashti Dashboard (OWL + pqGrid)',
|
||||
'author': 'Raman Marikanti',
|
||||
'depends': ['stock', 'web_grid','costing_mrp_bom'],
|
||||
|
|
|
|||
|
|
@ -112,6 +112,39 @@ class SamashtiDashboard(models.AbstractModel):
|
|||
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
|
||||
|
|
@ -152,3 +185,17 @@ class SamashtiDashboard(models.AbstractModel):
|
|||
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
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -172,16 +172,14 @@ export class SamashtiDashboard extends Component {
|
|||
async getSaleColumns(){
|
||||
return[
|
||||
{ title: "Sale Order", dataIndx: "sale_order", width: 100,filter: { type: 'textbox', condition: 'contain', listeners: ['keyup'] } },
|
||||
{ title: "Product Code", dataIndx: "product_code", width: 100,filter: { type: 'textbox', condition: 'contain', listeners: ['keyup'] } },
|
||||
{ title: "Product Name", dataIndx: "product_name", width: 280,filter: { type: 'textbox', condition: 'contain', listeners: ['keyup'] } },
|
||||
{ title: "Category", dataIndx: "category", width: 150 },
|
||||
{ title: "Customer", dataIndx: "customer", width: 280,filter: { type: 'textbox', condition: 'contain', listeners: ['keyup'] } },
|
||||
{ title: "Date", dataIndx: "date", width: 150 },
|
||||
{ title: "Quantity", dataIndx: "quantity", width: 120, dataType: "float", format: "#,###.00",summary: { type: "sum" },align: "right" },
|
||||
{ title: "Unit Cost", dataIndx: "unit_cost", width: 120, dataType: "float", format: "#,###.00",summary: { type: "sum" },align: "right" },
|
||||
{ title: "Unit Sale Price", dataIndx: "unit_sale_price", width: 120, dataType: "float", format: "#,###.00",summary: { type: "sum" },align: "right" },
|
||||
{ title: "Unit Margin", dataIndx: "margin", width: 120, dataType: "float", format: "#,###.00",summary: { type: "sum" },align: "right" },
|
||||
{ title: "Total Cost", dataIndx: "total_cost", width: 120, dataType: "float", format: "#,###.00",summary: { type: "sum" },align: "right" },
|
||||
{ title: "Total Sale Price", dataIndx: "total_sale_price", width: 120, dataType: "float", format: "#,###.00",summary: { type: "sum" },align: "right" },
|
||||
{ title: "Total Margin", dataIndx: "total_margin", width: 120, dataType: "float", format: "#,###.00",summary: { type: "sum" },align: "right" },
|
||||
{ title: "Weight", dataIndx: "weight", width: 150 },
|
||||
{ title: "Production Cost", dataIndx: "cost", width: 120, dataType: "float", format: "#,###.00",summary: { type: "sum" },align: "right" },
|
||||
{ title: "Sale Price", dataIndx: "sale_price", width: 120, dataType: "float", format: "#,###.00",summary: { type: "sum" },align: "right" },
|
||||
{ title: "Margin", 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" },
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
from . import models
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
'name': 'Asset Management',
|
||||
'version': '18.0',
|
||||
'category': 'Documents',
|
||||
'summary': 'Fixed Asset Management',
|
||||
'author': 'Raman Marikanti',
|
||||
'depends': ['mail', 'base'],
|
||||
|
||||
'data': [
|
||||
'data/ir_sequence.xml',
|
||||
'views/asset_category_view.xml',
|
||||
'views/asset_detail_view.xml',
|
||||
'views/asset_location_view.xml',
|
||||
'views/asset_move_view.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
|
||||
'license': 'LGPL-3',
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="sequence_asset_move" model="ir.sequence">
|
||||
<field name="name">Asset Move</field>
|
||||
<field name="code">asset.move</field>
|
||||
<field name="prefix">MOV/%(range_year)s/</field>
|
||||
<field name="padding">5</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
<record id="sequence_asset_detail" model="ir.sequence">
|
||||
<field name="name">Asset Detail</field>
|
||||
<field name="code">asset.detail</field>
|
||||
<field name="prefix">AST/%(range_year)s/</field>
|
||||
<field name="padding">5</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
from . import asset_detail
|
||||
from . import asset_move
|
||||
from . import asset_location
|
||||
from . import asset_category
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
from odoo import fields, models, api
|
||||
|
||||
|
||||
class AssetCategory(models.Model):
|
||||
_name = "asset.category"
|
||||
_description = "Asset Category"
|
||||
|
||||
name = fields.Char(string="Name")
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
from odoo import fields, models, api
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class AssetDetail(models.Model):
|
||||
_name = "asset.detail"
|
||||
_description = "Asset Detail"
|
||||
|
||||
name = fields.Char(string="Name")
|
||||
asset_image = fields.Binary(string="Image")
|
||||
category_id = fields.Many2one(comodel_name="asset.category", string="Category")
|
||||
asset_code = fields.Char(string="Asset Code")
|
||||
asset_model = fields.Char(string="Asset Model")
|
||||
serial_no = fields.Char(string="Serial No.")
|
||||
purchase_date = fields.Date(string="Purchase Date")
|
||||
purchase_value = fields.Float(string="Purchase Value")
|
||||
location_id = fields.Many2one(comodel_name="asset.location", string="Current Location")
|
||||
# employee_id = fields.Many2one(comodel_name="hr.employee", string="Employee")
|
||||
vendor_id = fields.Many2one(comodel_name="res.partner", string="Vendor")
|
||||
warranty_start = fields.Date(string="Warranty Start")
|
||||
warranty_end = fields.Date(string="Warranty End")
|
||||
note = fields.Html(string="Note")
|
||||
state = fields.Selection([('draft', 'New'), ('active', 'Active'), ('scrap', 'Scrap')], string='State', default="draft")
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
location_id = self.env["asset.location"].search([("is_default", "=", True)], limit=1)
|
||||
vals["asset_code"] = self.env["ir.sequence"].next_by_code("asset.detail", sequence_date=datetime.now().year) or "New"
|
||||
vals["location_id"] = location_id.id if location_id else None
|
||||
return super(AssetDetail, self).create(vals)
|
||||
|
||||
def scrap_asset(self):
|
||||
for asset_id in self:
|
||||
location_id = self.env["asset.location"].search([("is_scrap", "=", True)], limit=1)
|
||||
if location_id:
|
||||
asset_id.state = "scrap"
|
||||
|
||||
def confirm_asset(self):
|
||||
for asset_id in self:
|
||||
asset_id.state = "active"
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
from odoo import fields, models, api
|
||||
|
||||
|
||||
class AssetLocation(models.Model):
|
||||
_name = "asset.location"
|
||||
_description = "Asset Location"
|
||||
|
||||
name = fields.Char(string="Name")
|
||||
is_default = fields.Boolean(string="Default")
|
||||
is_scrap = fields.Boolean(string="Scrap")
|
||||
asset_line = fields.One2many(comodel_name="asset.detail", inverse_name="location_id")
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
from odoo import fields, models, api
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class AssetMove(models.Model):
|
||||
_name = "asset.move"
|
||||
_description = "Asset Move"
|
||||
|
||||
name = fields.Char(string="Name")
|
||||
location_id = fields.Many2one(comodel_name="asset.location", string="Source Location")
|
||||
location_dest_id = fields.Many2one(comodel_name="asset.location", string="Destination Location")
|
||||
asset_id = fields.Many2one(comodel_name="asset.detail", string="Asset")
|
||||
state = fields.Selection([('draft', 'Draft'),('done', 'Done'),('cancel', 'Cancel')], string='State', default="draft")
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
vals["name"] = self.env["ir.sequence"].next_by_code("asset.move", sequence_date=datetime.now().year) or "New"
|
||||
return super(AssetMove, self).create(vals)
|
||||
|
||||
@api.onchange("asset_id")
|
||||
def onchange_asset(self):
|
||||
self.location_id = self.asset_id.location_id.id
|
||||
|
||||
def move_asset(self):
|
||||
for asset_id in self:
|
||||
asset_id.asset_id.location_id = asset_id.location_dest_id.id
|
||||
asset_id.state = "done"
|
||||
|
||||
def cancel_move(self):
|
||||
for asset_id in self:
|
||||
asset_id.state = "cancel"
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
asset_category,asset.category,model_asset_category,,1,1,1,1
|
||||
asset_detail,asset.detail,model_asset_detail,,1,1,1,1
|
||||
asset_location,asset.location,model_asset_location,,1,1,1,1
|
||||
asset_move,asset.move,model_asset_move,,1,1,1,1
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:31255c2b3d454708d62a118e2a9b9e7526670ad0f5774acec8fb83db71d6b8fc
|
||||
size 43161
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<odoo>
|
||||
<record id="asset_category_list_view" model="ir.ui.view">
|
||||
<field name="name">Asset Category</field>
|
||||
<field name="model">asset.category</field>
|
||||
<field name="arch" type="xml">
|
||||
<list editable="top">
|
||||
<field name="name"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_asset_category" model="ir.actions.act_window">
|
||||
<field name="name">Asset Category</field>
|
||||
<field name="res_model">asset.category</field>
|
||||
<field name="view_mode">list</field>
|
||||
</record>
|
||||
<menuitem id="main_menu_assets" name="Asset Management"/>
|
||||
<menuitem id="menu_asset_configuration" name="Configuration" parent="main_menu_assets" sequence="2"/>
|
||||
<menuitem id="menu_asset_category" action="action_asset_category" parent="menu_asset_configuration"/>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<odoo>
|
||||
<record id="asset_detail_list_view" model="ir.ui.view">
|
||||
<field name="name">asset.detail.list.view</field>
|
||||
<field name="model">asset.detail</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="category_id"/>
|
||||
<field name="asset_model"/>
|
||||
<field name="serial_no"/>
|
||||
<field name="state"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record id="asset_detail_form_view" model="ir.ui.view">
|
||||
<field name="name">asset.detail.form.view</field>
|
||||
<field name="model">asset.detail</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<button name="confirm_asset" string="Confirm" class="btn-primary" type="object" invisible="state not in 'draft'"/>
|
||||
<button name="scrap_asset" string="Scrap" class="btn-primary" type="object" invisible="state not in 'scrap'"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,active"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<label class="oe_edit_only" for="name" string="Asset Name"/>
|
||||
<h1>
|
||||
<field name="name" placeholder="Name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="category_id" options="{'no_create_edit': True, 'no_create': True}"/>
|
||||
<field name="asset_code" readonly="1"/>
|
||||
<field name="asset_model"/>
|
||||
<field name="serial_no"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="purchase_date"/>
|
||||
<field name="purchase_value"/>
|
||||
<field name="location_id" options="{'no_create_edit': True, 'no_create': True}"/>
|
||||
<!-- <field name="employee_id" options="{'no_create_edit': True, 'no_create': True}"/>-->
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Warranty">
|
||||
<group>
|
||||
<group>
|
||||
<field name="vendor_id" options="{'no_create_edit': True, 'no_create': True}"/>
|
||||
<field name="warranty_start"/>
|
||||
<field name="warranty_end"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_asset_detail" model="ir.actions.act_window">
|
||||
<field name="name">Assets</field>
|
||||
<field name="res_model">asset.detail</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
<menuitem id="main_menu_asset" name="Asset" parent="main_menu_assets" sequence="1"/>
|
||||
<menuitem id="menu_asset_detail" action="action_asset_detail" parent="main_menu_asset"/>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<odoo>
|
||||
<record id="asset_location_list_view" model="ir.ui.view">
|
||||
<field name="name">Asset Location</field>
|
||||
<field name="model">asset.location</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="is_default"/>
|
||||
<field name="is_scrap"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record id="asset_location_form_view" model="ir.ui.view">
|
||||
<field name="name">asset.location.form.view</field>
|
||||
<field name="model">asset.location</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<label class="oe_edit_only" for="name" string="Location"/>
|
||||
<h1>
|
||||
<field name="name" placeholder="Name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="is_default"/>
|
||||
<field name="is_scrap"/>
|
||||
</group>
|
||||
<group/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Assets">
|
||||
<field name="asset_line" >
|
||||
<list string="Assets" editable="bottom" delete="0">
|
||||
<field name="location_id" column_invisible="1" />
|
||||
<field name="name"/>
|
||||
<field name="asset_code"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_asset_location" model="ir.actions.act_window">
|
||||
<field name="name">Asset Location</field>
|
||||
<field name="res_model">asset.location</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
<menuitem id="menu_asset_location" action="action_asset_location" parent="menu_asset_configuration"/>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<odoo>
|
||||
<record id="asset_move_list_view" model="ir.ui.view">
|
||||
<field name="name">asset.move.list.view</field>
|
||||
<field name="model">asset.move</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="asset_id"/>
|
||||
<field name="location_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="state"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
<record id="asset_move_form_view" model="ir.ui.view">
|
||||
<field name="name">asset.move.form.view</field>
|
||||
<field name="model">asset.move</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<button name="move_asset" string="Move" class="btn-primary" type="object" invisible="state not in 'draft'"/>
|
||||
<button name="cancel_move" string="Cancel" type="object" invisible="state not in 'draft'"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,done"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name" placeholder="Name" readonly="1"/>
|
||||
<field name="asset_id" domain="([('state', '=', 'active')])" options="{'no_create_edit': True, 'no_create': True}"/>
|
||||
<field name="location_id" domain="([('is_scrap', '=', False)])" options="{'no_create_edit': True, 'no_create': True}"/>
|
||||
<field name="location_dest_id" domain="([('is_scrap', '=', False)])" options="{'no_create_edit': True, 'no_create': True}"/>
|
||||
</group>
|
||||
<group/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_asset_move" model="ir.actions.act_window">
|
||||
<field name="name">Asset Move</field>
|
||||
<field name="res_model">asset.move</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
</record>
|
||||
<menuitem id="menu_asset_move" action="action_asset_move" parent="main_menu_asset"/>
|
||||
</odoo>
|
||||
|
|
@ -4,6 +4,7 @@ from email.policy import default
|
|||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError, UserError
|
||||
|
||||
|
||||
class Grn(models.Model):
|
||||
_name = 'grn'
|
||||
_description = 'Goods Receipt Note'
|
||||
|
|
@ -44,8 +45,36 @@ class Grn(models.Model):
|
|||
|
||||
def _get_product_catalog_order_data(self, products, **kwargs):
|
||||
res = super()._get_product_catalog_order_data(products, **kwargs)
|
||||
for product in products:
|
||||
res[product.id] |= {
|
||||
'price': product.standard_price,
|
||||
}
|
||||
return res
|
||||
|
||||
def _get_product_catalog_domain(self):
|
||||
"""Get the domain to search for products in the catalog.
|
||||
"""
|
||||
domain = [('company_id', 'in', [self.company_id.id, False]), ('type', '=', 'consu'), ('purchase_ok', '=', True)]
|
||||
return domain
|
||||
|
||||
def _update_order_line_info(self, product_id, quantity, **kwargs):
|
||||
self.ensure_one()
|
||||
pol = self.grn_line_ids.filtered(lambda line: line.product_id.id == product_id)
|
||||
if pol:
|
||||
if quantity != 0:
|
||||
pol.quantity = quantity
|
||||
else:
|
||||
pol.unlink()
|
||||
elif quantity > 0:
|
||||
pol = self.env['grn.lines'].create({
|
||||
'grn_id': self.id,
|
||||
'product_id': product_id,
|
||||
'quantity': quantity,
|
||||
})
|
||||
else:
|
||||
pass
|
||||
return 0
|
||||
|
||||
@api.depends('grn_line_ids')
|
||||
def _compute_total_amount(self):
|
||||
"""Compute the value of the field computed_field."""
|
||||
|
|
@ -55,8 +84,12 @@ class Grn(models.Model):
|
|||
amount += (line.quantity * line.price)
|
||||
record.total_amount = amount
|
||||
|
||||
|
||||
|
||||
def _get_product_catalog_lines_data(self):
|
||||
catalog_info = {
|
||||
'quantity': self.quantity,
|
||||
'price': self.product_id.standard_price,
|
||||
}
|
||||
return catalog_info
|
||||
|
||||
def button_action_confirm(self):
|
||||
"""Confirm the GRN and assign sequence and received user"""
|
||||
|
|
@ -155,7 +188,6 @@ class Grn(models.Model):
|
|||
'res_id': self.picking_id.id,
|
||||
}
|
||||
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
return super().create(vals_list)
|
||||
|
|
@ -170,10 +202,6 @@ class Grn(models.Model):
|
|||
) % self.name)
|
||||
return super().unlink()
|
||||
|
||||
def action_add_from_catalog(self):
|
||||
res = super().action_add_from_catalog()
|
||||
return res
|
||||
|
||||
|
||||
class GrnLines(models.Model):
|
||||
_name = 'grn.lines'
|
||||
|
|
@ -204,13 +232,10 @@ class GrnLines(models.Model):
|
|||
if len(duplicate_lines) > 1:
|
||||
raise UserError(_('The product %s already exists in the GRN.') % rec.product_id.display_name)
|
||||
|
||||
|
||||
def action_add_from_catalog(self):
|
||||
order = self.env['grn'].browse(self.env.context.get('order_id'))
|
||||
return order.with_context(child_field='grn_line_ids').action_add_from_catalog()
|
||||
|
||||
|
||||
|
||||
def unlink(self):
|
||||
if any(rec.grn_id.state not in ['cancel', 'draft'] for rec in self):
|
||||
raise UserError(_(
|
||||
|
|
|
|||
|
|
@ -33,9 +33,11 @@
|
|||
</group>
|
||||
<group>
|
||||
<field name="date" readonly="state != 'draft'"/>
|
||||
<field name="picking_id" readonly="1" invisible="not picking_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="note" readonly="state != 'draft'"/>
|
||||
</group>
|
||||
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="GRN Details">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': 'Grn Purchase',
|
||||
'version': '1.0',
|
||||
'summary': 'GRN LINK WITH Purchase',
|
||||
'description': '''
|
||||
Detailed description of the module
|
||||
''',
|
||||
'category': 'Purchase',
|
||||
'author': 'Raman Marikanti',
|
||||
'depends': ['base', 'mail', 'grn','purchase'],
|
||||
'data': [
|
||||
# 'security/ir.model.access.csv',
|
||||
'views/grn_purchase_views.xml',
|
||||
],
|
||||
'license': 'LGPL-3',
|
||||
'installable': True,
|
||||
'application': False,
|
||||
'auto_install': False,
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import grn_purchase
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import _,api, fields, models
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
|
||||
def _action_done(self):
|
||||
res = super(StockPicking, self)._action_done()
|
||||
for rec in self:
|
||||
if rec.purchase_id and rec.picking_type_id.code == 'incoming':
|
||||
grn = self.env['grn'].search([('picking_id','=', rec.id)])
|
||||
if not grn:
|
||||
grn_data = {
|
||||
'vendor_id':rec.partner_id.id,
|
||||
'date':fields.Datetime.now(),
|
||||
'location_id':rec.location_dest_id.id,
|
||||
'note':rec.purchase_id.name,
|
||||
'grn_line_ids':[]
|
||||
}
|
||||
for line in rec.move_ids.filtered(lambda x:x.product_id.type == 'consu'):
|
||||
grn_data['grn_line_ids'].append((0,0,{
|
||||
'product_id':line.product_id.id,
|
||||
'quantity':line.quantity,
|
||||
'product_uom_id':line.product_id.uom_id.id,
|
||||
'price':line.price_unit,
|
||||
}))
|
||||
new_grn = self.env['grn'].create(grn_data)
|
||||
new_grn.name = self.env['ir.sequence'].next_by_code('grn') or _('New')
|
||||
new_grn.picking_id = rec
|
||||
new_grn.state = 'done'
|
||||
rec.purchase_id.grn_ids |= new_grn
|
||||
elif grn and grn.state != 'done':
|
||||
grn.state = 'done'
|
||||
return res
|
||||
|
||||
|
||||
|
||||
class PurchaseOrder(models.Model):
|
||||
_inherit = "purchase.order"
|
||||
|
||||
grn_ids = fields.Many2many('grn', string="GRN")
|
||||
grn_count = fields.Integer('GRN Count', compute='_compute_grn_count')
|
||||
|
||||
@api.depends('grn_ids')
|
||||
def _compute_grn_count(self):
|
||||
self.grn_count = len(self.grn_ids)
|
||||
|
||||
def action_show_grn_ids(self):
|
||||
action = self.env['ir.actions.actions']._for_xml_id('grn.grn_action')
|
||||
action['domain'] = [('id', 'in', self.grn_ids.ids)]
|
||||
action['context'] = {}
|
||||
return action
|
||||
|
|
@ -0,0 +1 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="purchase_order_form_grn" model="ir.ui.view">
|
||||
<field name="name">purchase.order.inherited.form.grn</field>
|
||||
<field name="model">purchase.order</field>
|
||||
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button class="oe_stat_button" name="action_show_grn_ids" type="object" icon="fa-clipboard" invisible="grn_count == 0">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value"><field name="grn_count"/></span>
|
||||
<span class="o_stat_text">GRN's</span>
|
||||
</div>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
Loading…
Reference in New Issue