diff --git a/custom_addons/costing_mrp_bom/__manifest__.py b/custom_addons/costing_mrp_bom/__manifest__.py index d2ffd54db..8dc7641dc 100644 --- a/custom_addons/costing_mrp_bom/__manifest__.py +++ b/custom_addons/costing_mrp_bom/__manifest__.py @@ -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", diff --git a/custom_addons/costing_mrp_bom/models/sale_order_line.py b/custom_addons/costing_mrp_bom/models/sale_order_line.py index 0a5356ea1..3c3e498f8 100644 --- a/custom_addons/costing_mrp_bom/models/sale_order_line.py +++ b/custom_addons/costing_mrp_bom/models/sale_order_line.py @@ -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 + diff --git a/custom_addons/costing_mrp_bom/views/bom_view.xml b/custom_addons/costing_mrp_bom/views/bom_view.xml index b5d0996a5..bc465b96f 100644 --- a/custom_addons/costing_mrp_bom/views/bom_view.xml +++ b/custom_addons/costing_mrp_bom/views/bom_view.xml @@ -14,6 +14,47 @@ + + + + sale.order.form.inherit + sale.order + + + + + + + +
+
+
+
+
+
+
+ + + + + + + + + + + + + + mrp.production.inherited.form.decoration mrp.production diff --git a/custom_addons/dashboard/__manifest__.py b/custom_addons/dashboard/__manifest__.py index 27e1d6985..f7141f8d8 100644 --- a/custom_addons/dashboard/__manifest__.py +++ b/custom_addons/dashboard/__manifest__.py @@ -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'], diff --git a/custom_addons/dashboard/models/stock_dashboard.py b/custom_addons/dashboard/models/stock_dashboard.py index fc9313746..bdced02e0 100644 --- a/custom_addons/dashboard/models/stock_dashboard.py +++ b/custom_addons/dashboard/models/stock_dashboard.py @@ -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 + + + diff --git a/custom_addons/dashboard/static/src/components/pqgrid_dashboard/pqgrid_stock_dashboard.js b/custom_addons/dashboard/static/src/components/pqgrid_dashboard/pqgrid_stock_dashboard.js index d7227e9d0..ace0d611b 100644 --- a/custom_addons/dashboard/static/src/components/pqgrid_dashboard/pqgrid_stock_dashboard.js +++ b/custom_addons/dashboard/static/src/components/pqgrid_dashboard/pqgrid_stock_dashboard.js @@ -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" }, ] } diff --git a/custom_addons/fixed_asset_management/__init__.py b/custom_addons/fixed_asset_management/__init__.py new file mode 100644 index 000000000..9a7e03ede --- /dev/null +++ b/custom_addons/fixed_asset_management/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/custom_addons/fixed_asset_management/__manifest__.py b/custom_addons/fixed_asset_management/__manifest__.py new file mode 100644 index 000000000..102f9e41f --- /dev/null +++ b/custom_addons/fixed_asset_management/__manifest__.py @@ -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, +} diff --git a/custom_addons/fixed_asset_management/data/ir_sequence.xml b/custom_addons/fixed_asset_management/data/ir_sequence.xml new file mode 100644 index 000000000..ba83a09ed --- /dev/null +++ b/custom_addons/fixed_asset_management/data/ir_sequence.xml @@ -0,0 +1,18 @@ + + + + Asset Move + asset.move + MOV/%(range_year)s/ + 5 + + + + Asset Detail + asset.detail + AST/%(range_year)s/ + 5 + + + + \ No newline at end of file diff --git a/custom_addons/fixed_asset_management/models/__init__.py b/custom_addons/fixed_asset_management/models/__init__.py new file mode 100644 index 000000000..4159d86ed --- /dev/null +++ b/custom_addons/fixed_asset_management/models/__init__.py @@ -0,0 +1,4 @@ +from . import asset_detail +from . import asset_move +from . import asset_location +from . import asset_category \ No newline at end of file diff --git a/custom_addons/fixed_asset_management/models/asset_category.py b/custom_addons/fixed_asset_management/models/asset_category.py new file mode 100644 index 000000000..cf467e580 --- /dev/null +++ b/custom_addons/fixed_asset_management/models/asset_category.py @@ -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") \ No newline at end of file diff --git a/custom_addons/fixed_asset_management/models/asset_detail.py b/custom_addons/fixed_asset_management/models/asset_detail.py new file mode 100644 index 000000000..397211c93 --- /dev/null +++ b/custom_addons/fixed_asset_management/models/asset_detail.py @@ -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" \ No newline at end of file diff --git a/custom_addons/fixed_asset_management/models/asset_location.py b/custom_addons/fixed_asset_management/models/asset_location.py new file mode 100644 index 000000000..bab62a4cd --- /dev/null +++ b/custom_addons/fixed_asset_management/models/asset_location.py @@ -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") + diff --git a/custom_addons/fixed_asset_management/models/asset_move.py b/custom_addons/fixed_asset_management/models/asset_move.py new file mode 100644 index 000000000..8c274ad08 --- /dev/null +++ b/custom_addons/fixed_asset_management/models/asset_move.py @@ -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" \ No newline at end of file diff --git a/custom_addons/fixed_asset_management/security/ir.model.access.csv b/custom_addons/fixed_asset_management/security/ir.model.access.csv new file mode 100644 index 000000000..ea487de68 --- /dev/null +++ b/custom_addons/fixed_asset_management/security/ir.model.access.csv @@ -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 \ No newline at end of file diff --git a/custom_addons/fixed_asset_management/static/description/icon.png b/custom_addons/fixed_asset_management/static/description/icon.png new file mode 100644 index 000000000..231a4fbd0 --- /dev/null +++ b/custom_addons/fixed_asset_management/static/description/icon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:31255c2b3d454708d62a118e2a9b9e7526670ad0f5774acec8fb83db71d6b8fc +size 43161 diff --git a/custom_addons/fixed_asset_management/views/asset_category_view.xml b/custom_addons/fixed_asset_management/views/asset_category_view.xml new file mode 100644 index 000000000..5ed29ed97 --- /dev/null +++ b/custom_addons/fixed_asset_management/views/asset_category_view.xml @@ -0,0 +1,19 @@ + + + Asset Category + asset.category + + + + + + + + Asset Category + asset.category + list + + + + + \ No newline at end of file diff --git a/custom_addons/fixed_asset_management/views/asset_detail_view.xml b/custom_addons/fixed_asset_management/views/asset_detail_view.xml new file mode 100644 index 000000000..4e755786b --- /dev/null +++ b/custom_addons/fixed_asset_management/views/asset_detail_view.xml @@ -0,0 +1,68 @@ + + + asset.detail.list.view + asset.detail + + + + + + + + + + + + asset.detail.form.view + asset.detail + +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + Assets + asset.detail + list,form + + + +
diff --git a/custom_addons/fixed_asset_management/views/asset_location_view.xml b/custom_addons/fixed_asset_management/views/asset_location_view.xml new file mode 100644 index 000000000..a6946099f --- /dev/null +++ b/custom_addons/fixed_asset_management/views/asset_location_view.xml @@ -0,0 +1,53 @@ + + + Asset Location + asset.location + + + + + + + + + + asset.location.form.view + asset.location + +
+ +
+
+ + + + + + + + + + + + + + + + + + +
+
+
+
+ + Asset Location + asset.location + list,form + + +
diff --git a/custom_addons/fixed_asset_management/views/asset_move_view.xml b/custom_addons/fixed_asset_management/views/asset_move_view.xml new file mode 100644 index 000000000..70eab5ad2 --- /dev/null +++ b/custom_addons/fixed_asset_management/views/asset_move_view.xml @@ -0,0 +1,45 @@ + + + asset.move.list.view + asset.move + + + + + + + + + + + + asset.move.form.view + asset.move + +
+
+
+ + + + + + + + + + + +
+
+
+ + Asset Move + asset.move + list,form + + +
diff --git a/custom_addons/grn/models/grn.py b/custom_addons/grn/models/grn.py index e4cf4b886..6a315c7e0 100644 --- a/custom_addons/grn/models/grn.py +++ b/custom_addons/grn/models/grn.py @@ -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""" @@ -122,7 +155,7 @@ class Grn(models.Model): 'location_dest_id': self.location_id.id, 'location_id': picking_type.default_location_src_id.id, 'picking_type_id': picking_type.id, - 'partner_id':self.vendor_id.id + 'partner_id': self.vendor_id.id }) moves = [] @@ -140,7 +173,7 @@ class Grn(models.Model): picking.action_confirm() for move in picking: move.location_dest_id = self.location_id - picking.location_dest_id = self.location_id + picking.location_dest_id = self.location_id self.picking_id = picking def action_view_transfer(self): @@ -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' @@ -184,7 +212,7 @@ class GrnLines(models.Model): 'product.product', string='Product', ondelete="cascade", - domain=[('type', '!=', 'service'),('purchase_ok','=',True)], + domain=[('type', '!=', 'service'), ('purchase_ok', '=', True)], index=True ) product_uom_id = fields.Many2one(related='product_id.uom_id', string='Unit of Measure') @@ -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(_( diff --git a/custom_addons/grn/views/grn_views.xml b/custom_addons/grn/views/grn_views.xml index 82f8e74ce..04a36c261 100644 --- a/custom_addons/grn/views/grn_views.xml +++ b/custom_addons/grn/views/grn_views.xml @@ -33,9 +33,11 @@ + + + - diff --git a/custom_addons/grn_purchase/__init__.py b/custom_addons/grn_purchase/__init__.py new file mode 100644 index 000000000..5305644df --- /dev/null +++ b/custom_addons/grn_purchase/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models \ No newline at end of file diff --git a/custom_addons/grn_purchase/__manifest__.py b/custom_addons/grn_purchase/__manifest__.py new file mode 100644 index 000000000..e0dd50da1 --- /dev/null +++ b/custom_addons/grn_purchase/__manifest__.py @@ -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, +} \ No newline at end of file diff --git a/custom_addons/grn_purchase/models/__init__.py b/custom_addons/grn_purchase/models/__init__.py new file mode 100644 index 000000000..22b643d49 --- /dev/null +++ b/custom_addons/grn_purchase/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import grn_purchase \ No newline at end of file diff --git a/custom_addons/grn_purchase/models/grn_purchase.py b/custom_addons/grn_purchase/models/grn_purchase.py new file mode 100644 index 000000000..8130fdf8a --- /dev/null +++ b/custom_addons/grn_purchase/models/grn_purchase.py @@ -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 \ No newline at end of file diff --git a/custom_addons/grn_purchase/security/ir.model.access.csv b/custom_addons/grn_purchase/security/ir.model.access.csv new file mode 100644 index 000000000..97dd8b917 --- /dev/null +++ b/custom_addons/grn_purchase/security/ir.model.access.csv @@ -0,0 +1 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink diff --git a/custom_addons/grn_purchase/views/grn_purchase_views.xml b/custom_addons/grn_purchase/views/grn_purchase_views.xml new file mode 100644 index 000000000..55efa1c5a --- /dev/null +++ b/custom_addons/grn_purchase/views/grn_purchase_views.xml @@ -0,0 +1,20 @@ + + + + + purchase.order.inherited.form.grn + purchase.order + + + + + + + + + \ No newline at end of file