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.
349 lines
15 KiB
349 lines
15 KiB
# -*- coding: utf-8 -*-
|
|
################################################################################
|
|
#
|
|
# Cybrosys Technologies Pvt. Ltd.
|
|
#
|
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
|
|
# Author: Sumith Sivan(<https://www.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/>.
|
|
#
|
|
################################################################################
|
|
import io
|
|
import json
|
|
|
|
from odoo import api, fields, models
|
|
from odoo.exceptions import ValidationError
|
|
from odoo.tools import date_utils
|
|
|
|
try:
|
|
from odoo.tools.misc import xlsxwriter
|
|
except ImportError:
|
|
import xlsxwriter
|
|
|
|
|
|
class WizardReport(models.TransientModel):
|
|
"""Valuation report xlsx template """
|
|
_name = 'valuation.report'
|
|
|
|
company_id = fields.Many2one("res.company", sting="Company", required=True)
|
|
warehouse_ids = fields.Many2many("stock.warehouse", string="Warehouse",
|
|
required=True)
|
|
|
|
product_ids = fields.Many2many("product.product",
|
|
help="Select the products")
|
|
category_ids = fields.Many2many("product.category")
|
|
filter_by = fields.Selection(
|
|
[('product', 'Product'), ('category', 'Category')], string='Filter By')
|
|
start_date = fields.Datetime(string="Start Date")
|
|
end_date = fields.Datetime(string="End Date", )
|
|
summary = fields.Boolean(string="Summary", help="Print Summary Report")
|
|
|
|
@api.onchange('company_id')
|
|
def _compute_warehouse(self):
|
|
if self.company_id:
|
|
self.warehouse_ids = self.env['stock.warehouse'].search([
|
|
('company_id', '=', self.company_id.id)
|
|
]).ids
|
|
else:
|
|
self.warehouse_ids = False
|
|
return {'domain': {
|
|
'warehouse_ids': [('company_id', '=', self.company_id.id)]}}
|
|
|
|
def action_btn_pdf(self):
|
|
"""Function to print pdf report"""
|
|
product = self.env['product.product'].search(
|
|
[('detailed_type', '=', 'product')])
|
|
default_code = []
|
|
product_ids = []
|
|
category_ids = []
|
|
warehouse = [rec.name for rec in self.warehouse_ids]
|
|
|
|
if self.filter_by == "product":
|
|
default_code = [rec.default_code for rec in self.product_ids]
|
|
product_ids = [int(rec.id) for rec in self.product_ids]
|
|
|
|
if self.filter_by == "category":
|
|
category_ids = [int(rec.id) for rec in self.category_ids]
|
|
data = {
|
|
'from_date': self.start_date,
|
|
'end_date': self.end_date,
|
|
'my_company': self.company_id.name,
|
|
'my_company_id': self.company_id.id,
|
|
'currency': self.company_id.currency_id.name,
|
|
'warehouse': warehouse,
|
|
'filter_by': self.filter_by,
|
|
'products': product_ids,
|
|
'default_code': default_code,
|
|
'categories': category_ids,
|
|
'summary': self.summary,
|
|
'all_product': product,
|
|
|
|
}
|
|
return self.env.ref(
|
|
'inventory_valuation_report.action_report_valuation_report').report_action(
|
|
self,
|
|
data=data)
|
|
|
|
def action_btn_xlsx(self):
|
|
"""Function to print xlsx report"""
|
|
if self.warehouse_ids:
|
|
warehouse_names = [rec.name for rec in self.warehouse_ids]
|
|
warehouse = ', '.join(warehouse_names)
|
|
if str(self.start_date) > str(self.end_date):
|
|
raise ValidationError('Start Date must be less than End Date')
|
|
|
|
query = """select product_product.id as product_id,product_template.default_code as default_code ,
|
|
product_template.name->>'en_US' as name, product_category.name as category from product_template join
|
|
product_product on product_product.product_tmpl_id = product_template.id join product_category on
|
|
product_template.categ_id = product_category.id """
|
|
|
|
def get_data(res):
|
|
product_id = [rec['product_id'] for rec in res]
|
|
|
|
for i in range(len(res)):
|
|
product = self.env['product.product'].browse(product_id[i])
|
|
purchase_count = self.env['purchase.order.line'].search(
|
|
[('product_id', '=', product_id[i])])
|
|
valuation = self.env['stock.valuation.layer'].search(
|
|
[('product_id', '=', product_id[i])],
|
|
order="create_date desc", limit=1)
|
|
internal_locations = self.env['stock.location'].search(
|
|
[('usage', '=', 'internal')])
|
|
internal_qty = 0
|
|
|
|
for quant in internal_locations:
|
|
tracking = product.tracking
|
|
if tracking == 'lot':
|
|
lot_qty = self.env['stock.lot'].search(
|
|
[('product_id', '=', product_id[i])])
|
|
lot_qty_count = self.env['stock.quant'].search([
|
|
('product_id', '=', product_id[i]),
|
|
('lot_id', 'in', lot_qty.ids),
|
|
('location_id', '=', quant.id)
|
|
])
|
|
internal_qty += sum(
|
|
lot_qty_count.mapped('available_quantity'))
|
|
else:
|
|
internal_stock_quant = self.env['stock.quant'].search(
|
|
[('location_id', '=', quant.id),
|
|
('product_id', '=', product_id[i])])
|
|
internal_qty += internal_stock_quant.available_quantity
|
|
|
|
adjustment_rec = self.env['stock.quant'].search(
|
|
[('product_id', '=', product_id[i])],
|
|
order="create_date desc", limit=1)
|
|
adjustment = adjustment_rec.inventory_diff_quantity
|
|
res[i][
|
|
'costing_method'] = product.categ_id.property_cost_method
|
|
res[i]['standard_price'] = product.standard_price
|
|
res[i]['sale_qty'] = product.sales_count
|
|
res[i]['received_qty'] = sum(
|
|
purchase_count.mapped('product_uom_qty'))
|
|
res[i]['beginning'] = res[i]['received_qty'] - res[i][
|
|
'sale_qty']
|
|
res[i]['valuation'] = valuation.value
|
|
res[i]['internal'] = internal_qty
|
|
res[i]['adjustment'] = adjustment
|
|
return res
|
|
|
|
product_ids = [rec.id for rec in self.product_ids]
|
|
category_ids = [rec.id for rec in self.category_ids]
|
|
|
|
if self.company_id:
|
|
query += f""" join res_company on res_company.id=product_template.company_id where res_company.id = '{self.company_id.id}'"""
|
|
|
|
if self.start_date:
|
|
query += f""" and product_product.create_date >= '{self.start_date}'"""
|
|
|
|
if self.end_date:
|
|
query += f""" and product_product.create_date <= '{self.end_date}'"""
|
|
|
|
product = tuple(product_ids)
|
|
categories = tuple(category_ids)
|
|
|
|
if self.filter_by == 'product':
|
|
if len(product) == 1:
|
|
query += f""" and product_product.id = {product[0]} """
|
|
elif len(product) > 1:
|
|
query += f""" and product_product.id in {product} """
|
|
else:
|
|
raise ValidationError('No Product Found')
|
|
if self.filter_by == 'category':
|
|
if len(categories) == 1:
|
|
query += f""" and product_category.id = {categories[0]}"""
|
|
|
|
elif len(categories) > 1:
|
|
query += f""" and product_category.id in {categories} """
|
|
else:
|
|
raise ValidationError('No Category Found')
|
|
|
|
self.env.cr.execute(query)
|
|
record = self.env.cr.dictfetchall()
|
|
result = get_data(record)
|
|
data = {
|
|
'from_date': self.start_date,
|
|
'end_date': self.end_date,
|
|
'my_company': self.company_id.name,
|
|
'currency': self.company_id.currency_id.name,
|
|
'warehouse': warehouse,
|
|
'summary': self.summary,
|
|
'excel_result': result
|
|
}
|
|
return {
|
|
'type': 'ir.actions.report',
|
|
'report_type': 'xlsx',
|
|
'data': {
|
|
'model': 'valuation.report',
|
|
'output_format': 'xlsx',
|
|
'options': json.dumps(data, default=date_utils.json_default),
|
|
'report_name': 'Excel Report Name',
|
|
}
|
|
}
|
|
|
|
def get_xlsx_report(self, data, response):
|
|
"""xlsx report template"""
|
|
output = io.BytesIO()
|
|
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
|
|
sheet = workbook.add_worksheet()
|
|
cell_format = workbook.add_format({'font_size': '12px'})
|
|
head = workbook.add_format(
|
|
{'align': 'center', 'bold': True, 'font_size': '20px'})
|
|
txt = workbook.add_format({'align': 'center', 'font_size': '10px'})
|
|
columns = ['C:C', 'B:B', 'D:D', 'E:E', 'F:F', 'G:G', 'H:H', 'I:I',
|
|
'J:J', 'L:L', 'M:M']
|
|
for column in columns:
|
|
sheet.set_column(column, 20)
|
|
if data['summary']:
|
|
sheet.merge_range('B2:I3', 'Summary Valuation REPORT', head)
|
|
if data['from_date']:
|
|
sheet.write('B5', 'Start Date', cell_format)
|
|
sheet.write('B6', data['from_date'], txt)
|
|
if data['end_date']:
|
|
sheet.write('D5', 'End Date', cell_format)
|
|
sheet.write('D6', data['end_date'], txt)
|
|
if data['my_company']:
|
|
sheet.write('F5', 'Company', cell_format)
|
|
sheet.write('F6', data['my_company'], txt)
|
|
if data['warehouse']:
|
|
sheet.merge_range('G5:H5', 'Warehouse(s)', cell_format)
|
|
sheet.merge_range('G6:H6', data['warehouse'], txt)
|
|
if data['currency']:
|
|
sheet.write('I5', 'Currency', cell_format)
|
|
sheet.write('I6', data['currency'], txt)
|
|
sheet.write('B8', 'Sl.No', txt)
|
|
sheet.write('C8', 'Category', txt)
|
|
sheet.write('D8', 'Costing Method', txt)
|
|
sheet.write('E8', 'Cost Price', txt)
|
|
sheet.write('F8', 'Beginning', txt)
|
|
sheet.write('G8', 'Internal', txt)
|
|
sheet.write('H8', 'Received', txt)
|
|
sheet.write('I8', 'Sales', txt)
|
|
sheet.write('J8', 'Adjustment', txt)
|
|
sheet.write('K8', 'Ending', txt)
|
|
sheet.write('L8', 'Valuation', txt)
|
|
|
|
row_number = 9
|
|
column_number = 1
|
|
count = 1
|
|
for i in data['excel_result']:
|
|
sheet.write(row_number, column_number, count, txt)
|
|
sheet.write(row_number, column_number + 1, i['category'], txt)
|
|
sheet.write(row_number, column_number + 2, i['costing_method'],
|
|
txt)
|
|
sheet.write(row_number, column_number + 3, i['standard_price'],
|
|
txt)
|
|
sheet.write(row_number, column_number + 4,
|
|
i['received_qty'] - i['sale_qty'], txt)
|
|
sheet.write(row_number, column_number + 5, i['internal'], txt)
|
|
sheet.write(row_number, column_number + 6, i['received_qty'],
|
|
txt)
|
|
sheet.write(row_number, column_number + 7, i['sale_qty'], txt)
|
|
sheet.write(row_number, column_number + 8, i['adjustment'],
|
|
txt)
|
|
sheet.write(row_number, column_number + 9,
|
|
i['beginning'] + i['received_qty'] - i['sale_qty'] +
|
|
i['adjustment'], txt)
|
|
sheet.write(row_number, column_number + 10, i['valuation'],
|
|
txt)
|
|
|
|
row_number += 1
|
|
count += 1
|
|
workbook.close()
|
|
output.seek(0)
|
|
response.stream.write(output.read())
|
|
output.close()
|
|
else:
|
|
sheet.merge_range('B2:I3', 'Inventory Valuation REPORT', head)
|
|
if data['from_date']:
|
|
sheet.write('B5', 'Start Date', cell_format)
|
|
sheet.write('B6', data['from_date'], txt)
|
|
if data['end_date']:
|
|
sheet.write('D5', 'End Date', cell_format)
|
|
sheet.write('D6', data['end_date'], txt)
|
|
if data['my_company']:
|
|
sheet.write('F5', 'Company', cell_format)
|
|
sheet.write('F6', data['my_company'], txt)
|
|
if data['warehouse']:
|
|
sheet.merge_range('G5:H5', 'Warehouse(s)', cell_format)
|
|
sheet.merge_range('G6:H6', data['warehouse'], txt)
|
|
if data['currency']:
|
|
sheet.write('I5', 'Currency', cell_format)
|
|
sheet.write('I6', data['currency'], txt)
|
|
|
|
sheet.write('B9', 'Sl.No', txt)
|
|
sheet.write('C9', 'Default Code', txt)
|
|
sheet.write('D9', 'Name', txt)
|
|
sheet.write('E9', 'Category', txt)
|
|
sheet.write('F9', 'Costing Method', txt)
|
|
sheet.write('G9', 'Cost Price', txt)
|
|
sheet.write('H9', 'Beginning', txt)
|
|
sheet.write('I9', 'Internal', txt)
|
|
sheet.write('J9', 'Received', txt)
|
|
sheet.write('K9', 'Sales', txt)
|
|
sheet.write('L9', 'Adjustment', txt)
|
|
sheet.write('M9', 'Ending', txt)
|
|
sheet.write('N9', 'Valuation', txt)
|
|
|
|
row_number = 10
|
|
column_number = 1
|
|
count = 1
|
|
for i in data['excel_result']:
|
|
sheet.write(row_number, column_number, count, txt)
|
|
sheet.write(row_number, column_number + 1, i['default_code'],
|
|
txt)
|
|
sheet.write(row_number, column_number + 2, i['name'], txt)
|
|
sheet.write(row_number, column_number + 3, i['category'], txt)
|
|
sheet.write(row_number, column_number + 4, i['costing_method'],
|
|
txt)
|
|
sheet.write(row_number, column_number + 5, i['standard_price'],
|
|
txt)
|
|
sheet.write(row_number, column_number + 6,
|
|
i['received_qty'] - i['sale_qty'], txt)
|
|
sheet.write(row_number, column_number + 7, i['internal'], txt)
|
|
sheet.write(row_number, column_number + 8, i['received_qty'],
|
|
txt)
|
|
sheet.write(row_number, column_number + 9, i['sale_qty'], txt)
|
|
sheet.write(row_number, column_number + 10, i['adjustment'],
|
|
txt)
|
|
sheet.write(row_number, column_number + 11,
|
|
i['beginning'] + i['received_qty'] - i['sale_qty'] +
|
|
i['adjustment'], txt)
|
|
sheet.write(row_number, column_number + 12, i['valuation'],
|
|
txt)
|
|
row_number += 1
|
|
count += 1
|
|
workbook.close()
|
|
output.seek(0)
|
|
response.stream.write(output.read())
|
|
output.close()
|
|
|