You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
385 lines
18 KiB
385 lines
18 KiB
# -*- coding: utf-8 -*-
|
|
################################################################################
|
|
#
|
|
# Cybrosys Technologies Pvt. Ltd.
|
|
#
|
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
|
|
# Author: Saneen K (odoo@cybrosys.com)
|
|
#
|
|
# You can modify it under the terms of the GNU AFFERO
|
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
|
|
#
|
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
|
# (AGPL v3) along with this program.
|
|
# If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
################################################################################
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class StockPicking(models.Model):
|
|
"""Inherits stock.picking"""
|
|
_inherit = 'stock.picking'
|
|
|
|
barcode = fields.Char(string='Barcode', help="Product barcode")
|
|
invoice_count = fields.Integer(string='Invoices',
|
|
compute='_compute_invoice_count',
|
|
help="Count of invoices")
|
|
operation_code = fields.Selection(string="Operation code",
|
|
related='picking_type_id.code',
|
|
help="Operation code")
|
|
is_return = fields.Boolean(string="Is return picking",
|
|
help="Is this a return picking")
|
|
invoice_created = fields.Boolean(string='Invoice Created',
|
|
help="Is invoice is created")
|
|
|
|
@api.onchange('barcode')
|
|
def _onchange_barcode(self):
|
|
""" Scanning the barcode """
|
|
match = False
|
|
product_obj = self.env['product.product']
|
|
product_id = product_obj.search([('barcode', '=', self.barcode)])
|
|
if self.barcode and not product_id:
|
|
warning_mess = {
|
|
'title': _('Warning !'),
|
|
'message': _('No product is available for this barcode')
|
|
}
|
|
return {'warning': warning_mess}
|
|
if self.barcode and self.move_ids_without_package:
|
|
for line in self.move_ids_without_package:
|
|
if line.product_id.barcode == self.barcode:
|
|
line.quantity_done += 1
|
|
match = True
|
|
if self.barcode and not match:
|
|
if product_id:
|
|
warning_mess = {
|
|
'title': _('Warning !'),
|
|
'message': _('This product is not available in the order.'
|
|
'You can add this product by clicking the '
|
|
'"Add a line" and scan')}
|
|
return {'warning': warning_mess}
|
|
|
|
def write(self, vals):
|
|
"""Write values to order line"""
|
|
res = super(StockPicking, self).write(vals)
|
|
if vals.get('barcode') and self.move_ids_without_package:
|
|
for line in self.move_ids_without_package:
|
|
if line.product_id.barcode == vals['barcode']:
|
|
# Using a context flag to prevent multiple increments
|
|
if self.env.context.get('barcode_processed'):
|
|
line.with_context(barcode_processed=False).write(
|
|
{'quantity_done': line.quantity_done + 1})
|
|
self.barcode = None
|
|
return res
|
|
|
|
def _compute_invoice_count(self):
|
|
"""This computes function used to count the number of invoice
|
|
for the picking"""
|
|
for picking_id in self:
|
|
move_ids = picking_id.env['account.move'].search(
|
|
[('invoice_origin', '=', picking_id.name)])
|
|
if move_ids:
|
|
self.invoice_count = len(move_ids)
|
|
else:
|
|
self.invoice_count = 0
|
|
|
|
def create_invoice(self):
|
|
"""This is the function for creating customer invoice
|
|
from the picking"""
|
|
for picking_id in self:
|
|
current_user = self.env.uid
|
|
if picking_id.picking_type_id.code == 'outgoing':
|
|
customer_journal_id = picking_id.env[
|
|
'ir.config_parameter'].sudo().get_param(
|
|
'stock_move_invoice.customer_journal_id') or False
|
|
if not customer_journal_id:
|
|
raise UserError(
|
|
_("Please configure the journal from settings"))
|
|
invoice_line_list = []
|
|
for move_ids_without_package in picking_id. \
|
|
move_ids_without_package:
|
|
vals = (0, 0, {
|
|
'name': move_ids_without_package.description_picking,
|
|
'product_id': move_ids_without_package.product_id.id,
|
|
'price_unit': move_ids_without_package.product_id.
|
|
lst_price,
|
|
'account_id': move_ids_without_package.product_id.
|
|
property_account_income_id.id if
|
|
move_ids_without_package.product_id.
|
|
property_account_income_id
|
|
else move_ids_without_package.product_id.categ_id.
|
|
property_account_income_categ_id.id,
|
|
'tax_ids': [(6, 0, [
|
|
picking_id.company_id.account_sale_tax_id.id])],
|
|
'quantity': move_ids_without_package.quantity_done,
|
|
})
|
|
invoice_line_list.append(vals)
|
|
invoice = picking_id.env['account.move'].create({
|
|
'move_type': 'out_invoice',
|
|
'invoice_origin': picking_id.name,
|
|
'invoice_user_id': current_user,
|
|
'narration': picking_id.name,
|
|
'partner_id': picking_id.partner_id.id,
|
|
'currency_id': picking_id.env.user.company_id.
|
|
currency_id.id,
|
|
'journal_id': int(customer_journal_id),
|
|
'payment_reference': picking_id.name,
|
|
'picking_id': picking_id.id,
|
|
'invoice_line_ids': invoice_line_list,
|
|
'transfer_created': True
|
|
})
|
|
return invoice
|
|
|
|
def create_bill(self):
|
|
"""This is the function for creating vendor bill
|
|
from the picking"""
|
|
for picking_id in self:
|
|
current_user = self.env.uid
|
|
if picking_id.picking_type_id.code == 'incoming':
|
|
vendor_journal_id = picking_id.env[
|
|
'ir.config_parameter'].sudo().get_param(
|
|
'stock_move_invoice.vendor_journal_id') or False
|
|
if not vendor_journal_id:
|
|
raise UserError(
|
|
_("Please configure the journal from the settings."))
|
|
invoice_line_list = []
|
|
for move_ids_without_package in picking_id. \
|
|
move_ids_without_package:
|
|
vals = (0, 0, {
|
|
'name': move_ids_without_package.description_picking,
|
|
'product_id': move_ids_without_package.product_id.id,
|
|
'price_unit': move_ids_without_package.product_id.
|
|
lst_price,
|
|
'account_id': move_ids_without_package.product_id.
|
|
property_account_income_id.id if
|
|
move_ids_without_package.product_id.
|
|
property_account_income_id
|
|
else move_ids_without_package.product_id.categ_id.
|
|
property_account_income_categ_id.id,
|
|
'tax_ids': [(6, 0, [
|
|
picking_id.company_id.account_purchase_tax_id.id])],
|
|
'quantity': move_ids_without_package.quantity_done,
|
|
})
|
|
invoice_line_list.append(vals)
|
|
invoice = picking_id.env['account.move'].create({
|
|
'move_type': 'in_invoice',
|
|
'invoice_origin': picking_id.name,
|
|
'invoice_user_id': current_user,
|
|
'narration': picking_id.name,
|
|
'partner_id': picking_id.partner_id.id,
|
|
'currency_id': picking_id.env.user.company_id.
|
|
currency_id.id,
|
|
'journal_id': int(vendor_journal_id),
|
|
'payment_reference': picking_id.name,
|
|
'picking_id': picking_id.id,
|
|
'invoice_line_ids': invoice_line_list,
|
|
'transfer_created': True
|
|
})
|
|
return invoice
|
|
|
|
def create_customer_credit(self):
|
|
"""This is the function for creating customer credit note
|
|
from the picking"""
|
|
for picking_id in self:
|
|
current_user = picking_id.env.uid
|
|
if picking_id.picking_type_id.code == 'incoming':
|
|
customer_journal_id = picking_id.env[
|
|
'ir.config_parameter'].sudo() \
|
|
.get_param(
|
|
'stock_move_invoice.customer_journal_id') or False
|
|
if not customer_journal_id:
|
|
raise UserError(
|
|
_("Please configure the journal from settings"))
|
|
invoice_line_list = []
|
|
for move_ids_without_package in picking_id. \
|
|
move_ids_without_package:
|
|
vals = (0, 0, {
|
|
'name': move_ids_without_package.description_picking,
|
|
'product_id': move_ids_without_package.product_id.id,
|
|
'price_unit': move_ids_without_package.product_id.
|
|
lst_price,
|
|
'account_id': move_ids_without_package.product_id.
|
|
property_account_income_id.id if
|
|
move_ids_without_package.product_id.
|
|
property_account_income_id
|
|
else move_ids_without_package.product_id.categ_id.
|
|
property_account_income_categ_id.id,
|
|
'tax_ids': [(6, 0, [
|
|
picking_id.company_id.account_sale_tax_id.id])],
|
|
'quantity': move_ids_without_package.quantity_done,
|
|
})
|
|
invoice_line_list.append(vals)
|
|
invoice = picking_id.env['account.move'].create({
|
|
'move_type': 'out_refund',
|
|
'invoice_origin': picking_id.name,
|
|
'invoice_user_id': current_user,
|
|
'narration': picking_id.name,
|
|
'partner_id': picking_id.partner_id.id,
|
|
'currency_id': picking_id.env.user.company_id.
|
|
currency_id.id,
|
|
'journal_id': int(customer_journal_id),
|
|
'payment_reference': picking_id.name,
|
|
'picking_id': picking_id.id,
|
|
'invoice_line_ids': invoice_line_list
|
|
})
|
|
return invoice
|
|
|
|
def create_vendor_credit(self):
|
|
"""This is the function for creating refund
|
|
from the picking"""
|
|
for picking_id in self:
|
|
current_user = self.env.uid
|
|
if picking_id.picking_type_id.code == 'outgoing':
|
|
vendor_journal_id = picking_id.env[
|
|
'ir.config_parameter'].sudo().get_param(
|
|
'stock_move_invoice.vendor_journal_id') or False
|
|
if not vendor_journal_id:
|
|
raise UserError(
|
|
_("Please configure the journal from the settings."))
|
|
invoice_line_list = []
|
|
for move_ids_without_package in picking_id. \
|
|
move_ids_without_package:
|
|
vals = (0, 0, {
|
|
'name': move_ids_without_package.description_picking,
|
|
'product_id': move_ids_without_package.product_id.id,
|
|
'price_unit': move_ids_without_package.product_id.
|
|
lst_price,
|
|
'account_id': move_ids_without_package.product_id.
|
|
property_account_income_id.id if
|
|
move_ids_without_package.product_id.
|
|
property_account_income_id
|
|
else move_ids_without_package.product_id.categ_id.
|
|
property_account_income_categ_id.id,
|
|
'tax_ids': [(6, 0, [
|
|
picking_id.company_id.account_purchase_tax_id.id])],
|
|
'quantity': move_ids_without_package.quantity_done,
|
|
})
|
|
invoice_line_list.append(vals)
|
|
invoice = picking_id.env['account.move'].create({
|
|
'move_type': 'in_refund',
|
|
'invoice_origin': picking_id.name,
|
|
'invoice_user_id': current_user,
|
|
'narration': picking_id.name,
|
|
'partner_id': picking_id.partner_id.id,
|
|
'currency_id': picking_id.env.user.company_id.
|
|
currency_id.id,
|
|
'journal_id': int(vendor_journal_id),
|
|
'payment_reference': picking_id.name,
|
|
'picking_id': picking_id.id,
|
|
'invoice_line_ids': invoice_line_list
|
|
})
|
|
return invoice
|
|
|
|
def action_open_picking_invoice(self):
|
|
"""This is the function of the smart button which redirect to the
|
|
invoice related to the current picking"""
|
|
return {
|
|
'name': 'Invoices',
|
|
'type': 'ir.actions.act_window',
|
|
'view_mode': 'tree,form',
|
|
'res_model': 'account.move',
|
|
'domain': [('invoice_origin', '=', self.name)],
|
|
'context': {'create': False},
|
|
'target': 'current'
|
|
}
|
|
|
|
def action_open_picking_bills(self):
|
|
"""This is the function of the smart button which redirect to the
|
|
invoice related to the current picking"""
|
|
return {
|
|
'name': 'Bills',
|
|
'type': 'ir.actions.act_window',
|
|
'view_mode': 'tree,form',
|
|
'res_model': 'account.move',
|
|
'domain': [('invoice_origin', '=', self.name)],
|
|
'context': {'create': False},
|
|
'target': 'current'
|
|
}
|
|
|
|
@api.model
|
|
def get_operation_types(self):
|
|
"""rpc method of operation type tiles,operation type graph
|
|
Returns operation type details.
|
|
no_transfer - each operation type transfer count,
|
|
late - each operation type late count
|
|
waiting - each operation type waiting count
|
|
operation_type_name - have all the operation type name
|
|
backorder - each operation type backorders count
|
|
"""
|
|
no_transfer = {}
|
|
stock_picking_type = self.env['stock.picking.type'].search([])
|
|
stock_picking = self.env['stock.picking'].search([])
|
|
stock = []
|
|
length = []
|
|
names = []
|
|
late = {}
|
|
query = '''select stock_picking.picking_type_id, count(stock_picking.
|
|
picking_type_id) from stock_picking
|
|
inner join stock_picking_type on stock_picking.picking_type_id =
|
|
stock_picking_type.id
|
|
where stock_picking.company_id = %s and
|
|
stock_picking.state in ('assigned', 'waiting', 'confirmed') and
|
|
(has_deadline_issue = true or
|
|
date_deadline <= now() or scheduled_date <= now())
|
|
group by stock_picking.picking_type_id''' % self.env.company.id
|
|
self._cr.execute(query)
|
|
lates = self._cr.dictfetchall()
|
|
for rec in lates:
|
|
late.update({rec.get('picking_type_id'): rec.get('count')})
|
|
waiting = {}
|
|
backorder = {}
|
|
operation_type_name = {}
|
|
for type in stock_picking_type:
|
|
names.append(type.name)
|
|
orders = stock_picking.filtered(
|
|
lambda r: r.picking_type_id.id == type.id)
|
|
stock.append(len(orders))
|
|
length_stock_picking = len(orders)
|
|
length.append(len(stock_picking.filtered(
|
|
lambda r: r.picking_type_id.id == type.id)))
|
|
no_transfer.update({type.id: length_stock_picking})
|
|
operation_type_name.update({type.id: type.name})
|
|
if len(orders) > 0:
|
|
if len(orders.filtered(lambda r: r.state == 'confirmed')) > 0:
|
|
waiting.update({type.id: len(
|
|
orders.filtered(lambda r: r.state == 'confirmed'))})
|
|
if len(orders.mapped('backorder_id')) > 0:
|
|
backorder.update(
|
|
{type.id: len(orders.mapped('backorder_id'))})
|
|
return no_transfer, late, waiting, operation_type_name, backorder
|
|
|
|
@api.model
|
|
def get_product_category(self):
|
|
"""rpc method of product category graph
|
|
Returns product categories and category having on hand product quantity"""
|
|
category_ids = self.env['product.category'].search([])
|
|
category_name = []
|
|
product_count = []
|
|
for rec in category_ids:
|
|
name = rec.name
|
|
category_name.append(name)
|
|
count = rec.product_count
|
|
product_count.append(count)
|
|
value = {'name': category_name, 'count': product_count}
|
|
return value
|
|
|
|
@api.model
|
|
def get_locations(self):
|
|
"""rpc method of product location table
|
|
Returns locations and location having on hand product quantity"""
|
|
stock_quant_ids = self.env['stock.quant'].search([])
|
|
locations = stock_quant_ids.mapped('location_id')
|
|
value = {}
|
|
for rec in locations:
|
|
loc_stock_quant = stock_quant_ids.filtered(
|
|
lambda x: x.location_id == rec)
|
|
on_hand_quantity = sum(
|
|
loc_stock_quant.mapped('inventory_quantity_auto_apply'))
|
|
value[rec.name] = on_hand_quantity
|
|
return value
|
|
|