mirror of
https://github.com/OCA/stock-logistics-reporting.git
synced 2025-02-16 17:13:21 +02:00
[IMP] stock_card_report: black, isort
This commit is contained in:
@@ -2,23 +2,19 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
'name': 'Stock Card Report',
|
||||
'summary': 'Add stock card report on Inventory Reporting.',
|
||||
'version': '12.0.1.0.0',
|
||||
'category': 'Warehouse',
|
||||
'website': 'https://github.com/OCA/stock-logistics-reporting',
|
||||
'author': 'Ecosoft,Odoo Community Association (OCA)',
|
||||
'license': 'AGPL-3',
|
||||
'depends': [
|
||||
'stock',
|
||||
'date_range',
|
||||
'report_xlsx_helper',
|
||||
"name": "Stock Card Report",
|
||||
"summary": "Add stock card report on Inventory Reporting.",
|
||||
"version": "13.0.1.0.0",
|
||||
"category": "Warehouse",
|
||||
"website": "https://github.com/OCA/stock-logistics-reporting",
|
||||
"author": "Ecosoft, Odoo Community Association (OCA)",
|
||||
"license": "AGPL-3",
|
||||
"depends": ["stock", "date_range", "report_xlsx_helper"],
|
||||
"data": [
|
||||
"data/paper_format.xml",
|
||||
"data/report_data.xml",
|
||||
"reports/stock_card_report.xml",
|
||||
"wizard/stock_card_report_wizard_view.xml",
|
||||
],
|
||||
'data': [
|
||||
'data/paper_format.xml',
|
||||
'data/report_data.xml',
|
||||
'reports/stock_card_report.xml',
|
||||
'wizard/stock_card_report_wizard_view.xml',
|
||||
],
|
||||
'installable': True,
|
||||
"installable": True,
|
||||
}
|
||||
|
||||
@@ -5,52 +5,50 @@ from odoo import api, fields, models
|
||||
|
||||
|
||||
class StockCardView(models.TransientModel):
|
||||
_name = 'stock.card.view'
|
||||
_description = 'Stock Card View'
|
||||
_order = 'date'
|
||||
_name = "stock.card.view"
|
||||
_description = "Stock Card View"
|
||||
_order = "date"
|
||||
|
||||
date = fields.Datetime()
|
||||
product_id = fields.Many2one(comodel_name='product.product')
|
||||
product_id = fields.Many2one(comodel_name="product.product")
|
||||
product_qty = fields.Float()
|
||||
product_uom_qty = fields.Float()
|
||||
product_uom = fields.Many2one(comodel_name='uom.uom')
|
||||
product_uom = fields.Many2one(comodel_name="uom.uom")
|
||||
reference = fields.Char()
|
||||
location_id = fields.Many2one(comodel_name='stock.location')
|
||||
location_dest_id = fields.Many2one(comodel_name='stock.location')
|
||||
location_id = fields.Many2one(comodel_name="stock.location")
|
||||
location_dest_id = fields.Many2one(comodel_name="stock.location")
|
||||
is_initial = fields.Boolean()
|
||||
product_in = fields.Float()
|
||||
product_out = fields.Float()
|
||||
|
||||
|
||||
class StockCardReport(models.TransientModel):
|
||||
_name = 'report.stock.card.report'
|
||||
_description = 'Stock Card Report'
|
||||
_name = "report.stock.card.report"
|
||||
_description = "Stock Card Report"
|
||||
|
||||
# Filters fields, used for data computation
|
||||
date_from = fields.Date()
|
||||
date_to = fields.Date()
|
||||
product_ids = fields.Many2many(
|
||||
comodel_name='product.product',
|
||||
)
|
||||
location_id = fields.Many2one(
|
||||
comodel_name='stock.location',
|
||||
)
|
||||
product_ids = fields.Many2many(comodel_name="product.product")
|
||||
location_id = fields.Many2one(comodel_name="stock.location")
|
||||
|
||||
# Data fields, used to browse report data
|
||||
results = fields.Many2many(
|
||||
comodel_name='stock.card.view',
|
||||
compute='_compute_results',
|
||||
help='Use compute fields, so there is nothing store in database',
|
||||
comodel_name="stock.card.view",
|
||||
compute="_compute_results",
|
||||
help="Use compute fields, so there is nothing store in database",
|
||||
)
|
||||
|
||||
@api.multi
|
||||
def _compute_results(self):
|
||||
self.ensure_one()
|
||||
date_from = self.date_from or '0001-01-01'
|
||||
date_from = self.date_from or "0001-01-01"
|
||||
self.date_to = self.date_to or fields.Date.context_today(self)
|
||||
locations = self.env['stock.location'].search(
|
||||
[('id', 'child_of', [self.location_id.id])])
|
||||
self._cr.execute("""
|
||||
locations = self.env["stock.location"].search(
|
||||
[("id", "child_of", [self.location_id.id])]
|
||||
)
|
||||
self._cr.execute(
|
||||
"""
|
||||
SELECT move.date, move.product_id, move.product_qty,
|
||||
move.product_uom_qty, move.product_uom, move.reference,
|
||||
move.location_id, move.location_dest_id,
|
||||
@@ -64,37 +62,46 @@ class StockCardReport(models.TransientModel):
|
||||
and move.state = 'done' and move.product_id in %s
|
||||
and CAST(move.date AS date) <= %s
|
||||
ORDER BY move.date, move.reference
|
||||
""", (
|
||||
tuple(locations.ids), tuple(locations.ids), date_from,
|
||||
tuple(locations.ids), tuple(locations.ids),
|
||||
tuple(self.product_ids.ids), self.date_to))
|
||||
""",
|
||||
(
|
||||
tuple(locations.ids),
|
||||
tuple(locations.ids),
|
||||
date_from,
|
||||
tuple(locations.ids),
|
||||
tuple(locations.ids),
|
||||
tuple(self.product_ids.ids),
|
||||
self.date_to,
|
||||
),
|
||||
)
|
||||
stock_card_results = self._cr.dictfetchall()
|
||||
ReportLine = self.env['stock.card.view']
|
||||
ReportLine = self.env["stock.card.view"]
|
||||
self.results = [ReportLine.new(line).id for line in stock_card_results]
|
||||
|
||||
@api.multi
|
||||
def _get_initial(self, product_line):
|
||||
product_input_qty = sum(product_line.mapped('product_in'))
|
||||
product_output_qty = sum(product_line.mapped('product_out'))
|
||||
product_input_qty = sum(product_line.mapped("product_in"))
|
||||
product_output_qty = sum(product_line.mapped("product_out"))
|
||||
return product_input_qty - product_output_qty
|
||||
|
||||
@api.multi
|
||||
def print_report(self, report_type='qweb'):
|
||||
def print_report(self, report_type="qweb"):
|
||||
self.ensure_one()
|
||||
action = report_type == 'xlsx' and self.env.ref(
|
||||
'stock_card_report.action_stock_card_report_xlsx') or \
|
||||
self.env.ref('stock_card_report.action_stock_card_report_pdf')
|
||||
action = (
|
||||
report_type == "xlsx"
|
||||
and self.env.ref("stock_card_report.action_stock_card_report_xlsx")
|
||||
or self.env.ref("stock_card_report.action_stock_card_report_pdf")
|
||||
)
|
||||
return action.report_action(self, config=False)
|
||||
|
||||
def _get_html(self):
|
||||
result = {}
|
||||
rcontext = {}
|
||||
report = self.browse(self._context.get('active_id'))
|
||||
report = self.browse(self._context.get("active_id"))
|
||||
if report:
|
||||
rcontext['o'] = report
|
||||
result['html'] = self.env.ref(
|
||||
'stock_card_report.report_stock_card_report_html').render(
|
||||
rcontext)
|
||||
rcontext["o"] = report
|
||||
result["html"] = self.env.ref(
|
||||
"stock_card_report.report_stock_card_report_html"
|
||||
).render(rcontext)
|
||||
return result
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -2,180 +2,179 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import logging
|
||||
|
||||
from odoo import models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ReportStockCardReportXlsx(models.AbstractModel):
|
||||
_name = 'report.stock_card_report.report_stock_card_report_xlsx'
|
||||
_inherit = 'report.report_xlsx.abstract'
|
||||
_name = "report.stock_card_report.report_stock_card_report_xlsx"
|
||||
_inherit = "report.report_xlsx.abstract"
|
||||
|
||||
def generate_xlsx_report(self, workbook, data, objects):
|
||||
self._define_formats(workbook)
|
||||
for product in objects.product_ids:
|
||||
for ws_params in self._get_ws_params(workbook, data, product):
|
||||
ws_name = ws_params.get('ws_name')
|
||||
ws_name = ws_params.get("ws_name")
|
||||
ws_name = self._check_ws_name(ws_name)
|
||||
ws = workbook.add_worksheet(ws_name)
|
||||
generate_ws_method = getattr(
|
||||
self, ws_params['generate_ws_method'])
|
||||
generate_ws_method(
|
||||
workbook, ws, ws_params, data, objects, product)
|
||||
generate_ws_method = getattr(self, ws_params["generate_ws_method"])
|
||||
generate_ws_method(workbook, ws, ws_params, data, objects, product)
|
||||
|
||||
def _get_ws_params(self, wb, data, product):
|
||||
filter_template = {
|
||||
'1_date_from': {
|
||||
'header': {
|
||||
'value': 'Date from',
|
||||
},
|
||||
'data': {
|
||||
'value': self._render('date_from'),
|
||||
'format': self.format_tcell_date_center,
|
||||
"1_date_from": {
|
||||
"header": {"value": "Date from"},
|
||||
"data": {
|
||||
"value": self._render("date_from"),
|
||||
"format": self.format_tcell_date_center,
|
||||
},
|
||||
},
|
||||
'2_date_to': {
|
||||
'header': {
|
||||
'value': 'Date to',
|
||||
},
|
||||
'data': {
|
||||
'value': self._render('date_to'),
|
||||
'format': self.format_tcell_date_center,
|
||||
"2_date_to": {
|
||||
"header": {"value": "Date to"},
|
||||
"data": {
|
||||
"value": self._render("date_to"),
|
||||
"format": self.format_tcell_date_center,
|
||||
},
|
||||
},
|
||||
'3_location': {
|
||||
'header': {
|
||||
'value': 'Location',
|
||||
},
|
||||
'data': {
|
||||
'value': self._render('location'),
|
||||
'format': self.format_tcell_center,
|
||||
"3_location": {
|
||||
"header": {"value": "Location"},
|
||||
"data": {
|
||||
"value": self._render("location"),
|
||||
"format": self.format_tcell_center,
|
||||
},
|
||||
},
|
||||
}
|
||||
initial_template = {
|
||||
'1_ref': {
|
||||
'data': {
|
||||
'value': 'Initial',
|
||||
'format': self.format_tcell_center,
|
||||
},
|
||||
'colspan': 4,
|
||||
},
|
||||
'2_balance': {
|
||||
'data': {
|
||||
'value': self._render('balance'),
|
||||
'format': self.format_tcell_amount_right,
|
||||
"1_ref": {
|
||||
"data": {"value": "Initial", "format": self.format_tcell_center},
|
||||
"colspan": 4,
|
||||
},
|
||||
"2_balance": {
|
||||
"data": {
|
||||
"value": self._render("balance"),
|
||||
"format": self.format_tcell_amount_right,
|
||||
}
|
||||
},
|
||||
}
|
||||
stock_card_template = {
|
||||
'1_date': {
|
||||
'header': {
|
||||
'value': 'Date',
|
||||
"1_date": {
|
||||
"header": {"value": "Date"},
|
||||
"data": {
|
||||
"value": self._render("date"),
|
||||
"format": self.format_tcell_date_left,
|
||||
},
|
||||
'data': {
|
||||
'value': self._render('date'),
|
||||
'format': self.format_tcell_date_left,
|
||||
"width": 25,
|
||||
},
|
||||
'width': 25,
|
||||
"2_reference": {
|
||||
"header": {"value": "Reference"},
|
||||
"data": {
|
||||
"value": self._render("reference"),
|
||||
"format": self.format_tcell_left,
|
||||
},
|
||||
'2_reference': {
|
||||
'header': {
|
||||
'value': 'Reference',
|
||||
"width": 25,
|
||||
},
|
||||
'data': {
|
||||
'value': self._render('reference'),
|
||||
'format': self.format_tcell_left,
|
||||
"3_input": {
|
||||
"header": {"value": "Input"},
|
||||
"data": {"value": self._render("input")},
|
||||
"width": 25,
|
||||
},
|
||||
'width': 25,
|
||||
"4_output": {
|
||||
"header": {"value": "Output"},
|
||||
"data": {"value": self._render("output")},
|
||||
"width": 25,
|
||||
},
|
||||
'3_input': {
|
||||
'header': {
|
||||
'value': 'Input',
|
||||
},
|
||||
'data': {
|
||||
'value': self._render('input'),
|
||||
},
|
||||
'width': 25,
|
||||
},
|
||||
'4_output': {
|
||||
'header': {
|
||||
'value': 'Output',
|
||||
},
|
||||
'data': {
|
||||
'value': self._render('output'),
|
||||
},
|
||||
'width': 25,
|
||||
},
|
||||
'5_balance': {
|
||||
'header': {
|
||||
'value': 'Balance',
|
||||
},
|
||||
'data': {
|
||||
'value': self._render('balance'),
|
||||
},
|
||||
'width': 25,
|
||||
"5_balance": {
|
||||
"header": {"value": "Balance"},
|
||||
"data": {"value": self._render("balance")},
|
||||
"width": 25,
|
||||
},
|
||||
}
|
||||
|
||||
ws_params = {
|
||||
'ws_name': product.name,
|
||||
'generate_ws_method': '_stock_card_report',
|
||||
'title': 'Stock Card - {}'.format(product.name),
|
||||
'wanted_list_filter': [k for k in sorted(filter_template.keys())],
|
||||
'col_specs_filter': filter_template,
|
||||
'wanted_list_initial': [k for k in sorted(initial_template.keys())],
|
||||
'col_specs_initial': initial_template,
|
||||
'wanted_list': [k for k in sorted(stock_card_template.keys())],
|
||||
'col_specs': stock_card_template,
|
||||
"ws_name": product.name,
|
||||
"generate_ws_method": "_stock_card_report",
|
||||
"title": "Stock Card - {}".format(product.name),
|
||||
"wanted_list_filter": [k for k in sorted(filter_template.keys())],
|
||||
"col_specs_filter": filter_template,
|
||||
"wanted_list_initial": [k for k in sorted(initial_template.keys())],
|
||||
"col_specs_initial": initial_template,
|
||||
"wanted_list": [k for k in sorted(stock_card_template.keys())],
|
||||
"col_specs": stock_card_template,
|
||||
}
|
||||
return [ws_params]
|
||||
|
||||
def _stock_card_report(self, wb, ws, ws_params, data, objects, product):
|
||||
ws.set_portrait()
|
||||
ws.fit_to_pages(1, 0)
|
||||
ws.set_header(self.xls_headers['standard'])
|
||||
ws.set_footer(self.xls_footers['standard'])
|
||||
ws.set_header(self.xls_headers["standard"])
|
||||
ws.set_footer(self.xls_footers["standard"])
|
||||
self._set_column_width(ws, ws_params)
|
||||
# Title
|
||||
row_pos = 0
|
||||
row_pos = self._write_ws_title(ws, row_pos, ws_params, True)
|
||||
# Filter Table
|
||||
row_pos = self._write_line(
|
||||
ws, row_pos, ws_params, col_specs_section='header',
|
||||
ws,
|
||||
row_pos,
|
||||
ws_params,
|
||||
col_specs_section="header",
|
||||
default_format=self.format_theader_blue_center,
|
||||
col_specs='col_specs_filter', wanted_list='wanted_list_filter')
|
||||
col_specs="col_specs_filter",
|
||||
wanted_list="wanted_list_filter",
|
||||
)
|
||||
row_pos = self._write_line(
|
||||
ws, row_pos, ws_params, col_specs_section='data',
|
||||
ws,
|
||||
row_pos,
|
||||
ws_params,
|
||||
col_specs_section="data",
|
||||
render_space={
|
||||
'date_from': objects.date_from or '',
|
||||
'date_to': objects.date_to or '',
|
||||
'location': objects.location_id.display_name or '',
|
||||
"date_from": objects.date_from or "",
|
||||
"date_to": objects.date_to or "",
|
||||
"location": objects.location_id.display_name or "",
|
||||
},
|
||||
col_specs='col_specs_filter', wanted_list='wanted_list_filter')
|
||||
col_specs="col_specs_filter",
|
||||
wanted_list="wanted_list_filter",
|
||||
)
|
||||
row_pos += 1
|
||||
# Stock Card Table
|
||||
row_pos = self._write_line(
|
||||
ws, row_pos, ws_params, col_specs_section='header',
|
||||
default_format=self.format_theader_blue_center)
|
||||
ws,
|
||||
row_pos,
|
||||
ws_params,
|
||||
col_specs_section="header",
|
||||
default_format=self.format_theader_blue_center,
|
||||
)
|
||||
ws.freeze_panes(row_pos, 0)
|
||||
balance = objects._get_initial(objects.results.filtered(
|
||||
lambda l: l.product_id == product and l.is_initial))
|
||||
balance = objects._get_initial(
|
||||
objects.results.filtered(lambda l: l.product_id == product and l.is_initial)
|
||||
)
|
||||
row_pos = self._write_line(
|
||||
ws, row_pos, ws_params, col_specs_section='data',
|
||||
render_space={'balance': balance}, col_specs='col_specs_initial',
|
||||
wanted_list='wanted_list_initial')
|
||||
ws,
|
||||
row_pos,
|
||||
ws_params,
|
||||
col_specs_section="data",
|
||||
render_space={"balance": balance},
|
||||
col_specs="col_specs_initial",
|
||||
wanted_list="wanted_list_initial",
|
||||
)
|
||||
product_lines = objects.results.filtered(
|
||||
lambda l: l.product_id == product and not l.is_initial)
|
||||
lambda l: l.product_id == product and not l.is_initial
|
||||
)
|
||||
for line in product_lines:
|
||||
balance += line.product_in - line.product_out
|
||||
row_pos = self._write_line(
|
||||
ws, row_pos, ws_params, col_specs_section='data',
|
||||
ws,
|
||||
row_pos,
|
||||
ws_params,
|
||||
col_specs_section="data",
|
||||
render_space={
|
||||
'date': line.date or '',
|
||||
'reference': line.reference or '',
|
||||
'input': line.product_in or 0,
|
||||
'output': line.product_out or 0,
|
||||
'balance': balance,
|
||||
"date": line.date or "",
|
||||
"reference": line.reference or "",
|
||||
"input": line.product_in or 0,
|
||||
"output": line.product_out or 0,
|
||||
"balance": balance,
|
||||
},
|
||||
default_format=self.format_tcell_amount_right)
|
||||
default_format=self.format_tcell_amount_right,
|
||||
)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# Copyright 2019 Ecosoft Co., Ltd. (http://ecosoft.co.th)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import time
|
||||
import logging
|
||||
import time
|
||||
from datetime import date
|
||||
|
||||
from odoo.tests import common
|
||||
from odoo.tools import test_reports
|
||||
|
||||
@@ -11,213 +12,246 @@ _logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestStockCard(common.TransactionCase):
|
||||
|
||||
def setUp(cls):
|
||||
super(TestStockCard, cls).setUp()
|
||||
def setUp(self):
|
||||
super(TestStockCard, self).setUp()
|
||||
|
||||
# Create uom:
|
||||
uom_id = cls.ref('uom.product_uom_unit')
|
||||
uom_id = self.ref("uom.product_uom_unit")
|
||||
|
||||
# Create products:
|
||||
cls.product_A = cls.env['product.product'].create({
|
||||
'name': 'Product A',
|
||||
'type': 'product',
|
||||
'uom_id': uom_id,
|
||||
'uom_po_id': uom_id,
|
||||
})
|
||||
self.product_A = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product A",
|
||||
"type": "product",
|
||||
"uom_id": uom_id,
|
||||
"uom_po_id": uom_id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create location:
|
||||
cls.location_1 = cls.env.ref('stock.stock_location_stock')
|
||||
cls.location_2 = cls.env.ref('stock.stock_location_customers')
|
||||
self.location_1 = self.env.ref("stock.stock_location_stock")
|
||||
self.location_2 = self.env.ref("stock.stock_location_customers")
|
||||
|
||||
# Create operation type:
|
||||
operation_type = cls.env.ref('stock.picking_type_in')
|
||||
operation_type = self.env.ref("stock.picking_type_in")
|
||||
|
||||
# Create stock picking:
|
||||
picking = cls.env['stock.picking'].create({
|
||||
'location_id': cls.location_2.id,
|
||||
'location_dest_id': cls.location_1.id,
|
||||
'picking_type_id': operation_type.id,
|
||||
})
|
||||
cls.env['stock.move'].create({
|
||||
'name': cls.product_A.name,
|
||||
'product_id': cls.product_A.id,
|
||||
'product_uom_qty': 50.000,
|
||||
'product_uom': cls.product_A.uom_id.id,
|
||||
'picking_id': picking.id,
|
||||
'location_id': cls.location_2.id,
|
||||
'location_dest_id': cls.location_1.id,
|
||||
})
|
||||
picking = self.env["stock.picking"].create(
|
||||
{
|
||||
"location_id": self.location_2.id,
|
||||
"location_dest_id": self.location_1.id,
|
||||
"picking_type_id": operation_type.id,
|
||||
}
|
||||
)
|
||||
self.env["stock.move"].create(
|
||||
{
|
||||
"name": self.product_A.name,
|
||||
"product_id": self.product_A.id,
|
||||
"product_uom_qty": 50.000,
|
||||
"product_uom": self.product_A.uom_id.id,
|
||||
"picking_id": picking.id,
|
||||
"location_id": self.location_2.id,
|
||||
"location_dest_id": self.location_1.id,
|
||||
}
|
||||
)
|
||||
picking.action_confirm()
|
||||
picking.move_ids_without_package.quantity_done = 50.000
|
||||
picking.button_validate()
|
||||
|
||||
cls.model = cls._getReportModel()
|
||||
self.model = self._getReportModel()
|
||||
|
||||
cls.qweb_report_name = cls._getQwebReportName()
|
||||
cls.xlsx_report_name = cls._getXlsxReportName()
|
||||
cls.xlsx_action_name = cls._getXlsxReportActionName()
|
||||
self.qweb_report_name = self._getQwebReportName()
|
||||
self.xlsx_report_name = self._getXlsxReportName()
|
||||
self.xlsx_action_name = self._getXlsxReportActionName()
|
||||
|
||||
cls.report_title = cls._getReportTitle()
|
||||
self.report_title = self._getReportTitle()
|
||||
|
||||
cls.base_filters = cls._getBaseFilters()
|
||||
self.base_filters = self._getBaseFilters()
|
||||
|
||||
cls.report = cls.model.create(cls.base_filters)
|
||||
cls.report._compute_results()
|
||||
self.report = self.model.create(self.base_filters)
|
||||
self.report._compute_results()
|
||||
|
||||
def test_html(self):
|
||||
test_reports.try_report(self.env.cr, self.env.uid,
|
||||
test_reports.try_report(
|
||||
self.env.cr,
|
||||
self.env.uid,
|
||||
self.qweb_report_name,
|
||||
[self.report.id],
|
||||
report_type='qweb-html')
|
||||
report_type="qweb-html",
|
||||
)
|
||||
|
||||
def test_qweb(self):
|
||||
test_reports.try_report(self.env.cr, self.env.uid,
|
||||
test_reports.try_report(
|
||||
self.env.cr,
|
||||
self.env.uid,
|
||||
self.qweb_report_name,
|
||||
[self.report.id],
|
||||
report_type='qweb-pdf')
|
||||
report_type="qweb-pdf",
|
||||
)
|
||||
|
||||
def test_xlsx(self):
|
||||
test_reports.try_report(self.env.cr, self.env.uid,
|
||||
test_reports.try_report(
|
||||
self.env.cr,
|
||||
self.env.uid,
|
||||
self.xlsx_report_name,
|
||||
[self.report.id],
|
||||
report_type='xlsx')
|
||||
report_type="xlsx",
|
||||
)
|
||||
|
||||
def test_print(self):
|
||||
self.report.print_report('qweb')
|
||||
self.report.print_report('xlsx')
|
||||
self.report.print_report("qweb")
|
||||
self.report.print_report("xlsx")
|
||||
|
||||
def _getReportModel(self):
|
||||
return self.env['report.stock.card.report']
|
||||
return self.env["report.stock.card.report"]
|
||||
|
||||
def _getQwebReportName(self):
|
||||
return 'stock_card_report.report_stock_card_report_pdf'
|
||||
return "stock_card_report.report_stock_card_report_pdf"
|
||||
|
||||
def _getXlsxReportName(self):
|
||||
return 'stock_card_report.report_stock_card_report_xlsx'
|
||||
return "stock_card_report.report_stock_card_report_xlsx"
|
||||
|
||||
def _getXlsxReportActionName(self):
|
||||
return 'stock_card_report.action_report_stock_card_report_xlsx'
|
||||
return "stock_card_report.action_report_stock_card_report_xlsx"
|
||||
|
||||
def _getReportTitle(self):
|
||||
return 'Stock Card Report'
|
||||
return "Stock Card Report"
|
||||
|
||||
def _getBaseFilters(self):
|
||||
return {
|
||||
'product_ids': [(6, 0, [self.product_A.id])],
|
||||
'location_id': self.location_1.id,
|
||||
"product_ids": [(6, 0, [self.product_A.id])],
|
||||
"location_id": self.location_1.id,
|
||||
}
|
||||
|
||||
|
||||
class TestStockCardReport(common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestStockCardReport, self).setUp()
|
||||
|
||||
# Create uom:
|
||||
uom_id = self.ref('uom.product_uom_unit')
|
||||
uom_id = self.ref("uom.product_uom_unit")
|
||||
|
||||
# Create products:
|
||||
self.product_A = self.env['product.product'].create({
|
||||
'name': 'Product A',
|
||||
'type': 'product',
|
||||
'uom_id': uom_id,
|
||||
'uom_po_id': uom_id,
|
||||
})
|
||||
self.product_B = self.env['product.product'].create({
|
||||
'name': 'Product B',
|
||||
'type': 'product',
|
||||
'uom_id': uom_id,
|
||||
'uom_po_id': uom_id,
|
||||
})
|
||||
self.product_A = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product A",
|
||||
"type": "product",
|
||||
"uom_id": uom_id,
|
||||
"uom_po_id": uom_id,
|
||||
}
|
||||
)
|
||||
self.product_B = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product B",
|
||||
"type": "product",
|
||||
"uom_id": uom_id,
|
||||
"uom_po_id": uom_id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create location:
|
||||
self.location_1 = self.env.ref('stock.stock_location_stock')
|
||||
self.location_2 = self.env.ref('stock.stock_location_customers')
|
||||
self.location_1 = self.env.ref("stock.stock_location_stock")
|
||||
self.location_2 = self.env.ref("stock.stock_location_customers")
|
||||
|
||||
# Create operation type:
|
||||
operation_type = self.env.ref('stock.picking_type_in')
|
||||
operation_type = self.env.ref("stock.picking_type_in")
|
||||
|
||||
# Create stock picking:
|
||||
picking_1 = self.env['stock.picking'].create({
|
||||
'location_id': self.location_2.id,
|
||||
'location_dest_id': self.location_1.id,
|
||||
'picking_type_id': operation_type.id,
|
||||
})
|
||||
self.env['stock.move'].create({
|
||||
'name': self.product_A.name,
|
||||
'product_id': self.product_A.id,
|
||||
'product_uom_qty': 50.000,
|
||||
'product_uom': self.product_A.uom_id.id,
|
||||
'picking_id': picking_1.id,
|
||||
'location_id': self.location_2.id,
|
||||
'location_dest_id': self.location_1.id,
|
||||
})
|
||||
picking_1 = self.env["stock.picking"].create(
|
||||
{
|
||||
"location_id": self.location_2.id,
|
||||
"location_dest_id": self.location_1.id,
|
||||
"picking_type_id": operation_type.id,
|
||||
}
|
||||
)
|
||||
self.env["stock.move"].create(
|
||||
{
|
||||
"name": self.product_A.name,
|
||||
"product_id": self.product_A.id,
|
||||
"product_uom_qty": 50.000,
|
||||
"product_uom": self.product_A.uom_id.id,
|
||||
"picking_id": picking_1.id,
|
||||
"location_id": self.location_2.id,
|
||||
"location_dest_id": self.location_1.id,
|
||||
}
|
||||
)
|
||||
picking_1.action_confirm()
|
||||
picking_1.move_ids_without_package.quantity_done = 50.000
|
||||
picking_1.button_validate()
|
||||
|
||||
picking_2 = self.env['stock.picking'].create({
|
||||
'location_id': self.location_2.id,
|
||||
'location_dest_id': self.location_1.id,
|
||||
'picking_type_id': operation_type.id,
|
||||
})
|
||||
self.env['stock.move'].create({
|
||||
'name': self.product_B.name,
|
||||
'product_id': self.product_B.id,
|
||||
'product_uom_qty': 100.000,
|
||||
'product_uom': self.product_B.uom_id.id,
|
||||
'picking_id': picking_2.id,
|
||||
'location_id': self.location_2.id,
|
||||
'location_dest_id': self.location_1.id,
|
||||
})
|
||||
picking_2 = self.env["stock.picking"].create(
|
||||
{
|
||||
"location_id": self.location_2.id,
|
||||
"location_dest_id": self.location_1.id,
|
||||
"picking_type_id": operation_type.id,
|
||||
}
|
||||
)
|
||||
self.env["stock.move"].create(
|
||||
{
|
||||
"name": self.product_B.name,
|
||||
"product_id": self.product_B.id,
|
||||
"product_uom_qty": 100.000,
|
||||
"product_uom": self.product_B.uom_id.id,
|
||||
"picking_id": picking_2.id,
|
||||
"location_id": self.location_2.id,
|
||||
"location_dest_id": self.location_1.id,
|
||||
}
|
||||
)
|
||||
picking_2.action_confirm()
|
||||
picking_2.move_ids_without_package.quantity_done = 100.000
|
||||
picking_2.button_validate()
|
||||
|
||||
def test_reports(self):
|
||||
report = self.env['report.stock.card.report'].create({
|
||||
'product_ids': [(6, 0, [self.product_A.id, self.product_B.id])],
|
||||
'location_id': self.location_1.id,
|
||||
})
|
||||
report = self.env["report.stock.card.report"].create(
|
||||
{
|
||||
"product_ids": [(6, 0, [self.product_A.id, self.product_B.id])],
|
||||
"location_id": self.location_1.id,
|
||||
}
|
||||
)
|
||||
report._compute_results()
|
||||
report.print_report('qweb')
|
||||
report.print_report('xlsx')
|
||||
report.print_report("qweb")
|
||||
report.print_report("xlsx")
|
||||
|
||||
def test_get_report_html(self):
|
||||
report = self.env['report.stock.card.report'].create({
|
||||
'product_ids': [(6, 0, [self.product_A.id, self.product_B.id])],
|
||||
'location_id': self.location_1.id,
|
||||
})
|
||||
report = self.env["report.stock.card.report"].create(
|
||||
{
|
||||
"product_ids": [(6, 0, [self.product_A.id, self.product_B.id])],
|
||||
"location_id": self.location_1.id,
|
||||
}
|
||||
)
|
||||
report._compute_results()
|
||||
report.get_html(given_context={
|
||||
'active_id': report.id
|
||||
})
|
||||
report.get_html(given_context={"active_id": report.id})
|
||||
|
||||
def test_wizard_date_range(self):
|
||||
date_range = self.env['date.range']
|
||||
self.type = self.env['date.range.type'].create(
|
||||
{'name': 'Month',
|
||||
'company_id': False,
|
||||
'allow_overlap': False})
|
||||
dt = date_range.create({
|
||||
'name': 'FiscalYear',
|
||||
'date_start': time.strftime('%Y-%m-01'),
|
||||
'date_end': time.strftime('%Y-%m-28'),
|
||||
'type_id': self.type.id,
|
||||
})
|
||||
wizard = self.env['stock.card.report.wizard'].create(
|
||||
{'date_range_id': dt.id,
|
||||
'date_from': time.strftime('%Y-%m-28'),
|
||||
'date_to': time.strftime('%Y-%m-01'),
|
||||
'product_ids': [(6, 0, [self.product_A.id, self.product_B.id])],
|
||||
'location_id': self.location_1.id})
|
||||
date_range = self.env["date.range"]
|
||||
self.type = self.env["date.range.type"].create(
|
||||
{"name": "Month", "company_id": False, "allow_overlap": False}
|
||||
)
|
||||
dt = date_range.create(
|
||||
{
|
||||
"name": "FiscalYear",
|
||||
"date_start": time.strftime("%Y-%m-01"),
|
||||
"date_end": time.strftime("%Y-%m-28"),
|
||||
"type_id": self.type.id,
|
||||
}
|
||||
)
|
||||
wizard = self.env["stock.card.report.wizard"].create(
|
||||
{
|
||||
"date_range_id": dt.id,
|
||||
"date_from": time.strftime("%Y-%m-28"),
|
||||
"date_to": time.strftime("%Y-%m-01"),
|
||||
"product_ids": [(6, 0, [self.product_A.id, self.product_B.id])],
|
||||
"location_id": self.location_1.id,
|
||||
}
|
||||
)
|
||||
wizard._onchange_date_range_id()
|
||||
self.assertEqual(wizard.date_from, date(
|
||||
date.today().year, date.today().month, 1))
|
||||
self.assertEqual(wizard.date_to, date(
|
||||
date.today().year, date.today().month, 28))
|
||||
wizard._export('qweb-pdf')
|
||||
self.assertEqual(
|
||||
wizard.date_from, date(date.today().year, date.today().month, 1)
|
||||
)
|
||||
self.assertEqual(
|
||||
wizard.date_to, date(date.today().year, date.today().month, 28)
|
||||
)
|
||||
wizard._export("qweb-pdf")
|
||||
wizard.button_export_html()
|
||||
wizard.button_export_pdf()
|
||||
wizard.button_export_xlsx()
|
||||
|
||||
@@ -2,36 +2,25 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
from odoo.tools import pycompat
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
|
||||
class StockCardReportWizard(models.TransientModel):
|
||||
_name = 'stock.card.report.wizard'
|
||||
_description = 'Stock Card Report Wizard'
|
||||
_name = "stock.card.report.wizard"
|
||||
_description = "Stock Card Report Wizard"
|
||||
|
||||
date_range_id = fields.Many2one(
|
||||
comodel_name='date.range',
|
||||
string='Period',
|
||||
)
|
||||
date_from = fields.Date(
|
||||
string='Start Date',
|
||||
)
|
||||
date_to = fields.Date(
|
||||
string='End Date',
|
||||
)
|
||||
date_range_id = fields.Many2one(comodel_name="date.range", string="Period")
|
||||
date_from = fields.Date(string="Start Date")
|
||||
date_to = fields.Date(string="End Date")
|
||||
location_id = fields.Many2one(
|
||||
comodel_name='stock.location',
|
||||
string='Location',
|
||||
required=True,
|
||||
comodel_name="stock.location", string="Location", required=True
|
||||
)
|
||||
product_ids = fields.Many2many(
|
||||
comodel_name='product.product',
|
||||
string='Products',
|
||||
required=True,
|
||||
comodel_name="product.product", string="Products", required=True
|
||||
)
|
||||
|
||||
@api.onchange('date_range_id')
|
||||
@api.onchange("date_range_id")
|
||||
def _onchange_date_range_id(self):
|
||||
self.date_from = self.date_range_id.date_start
|
||||
self.date_to = self.date_range_id.date_end
|
||||
@@ -39,41 +28,40 @@ class StockCardReportWizard(models.TransientModel):
|
||||
@api.multi
|
||||
def button_export_html(self):
|
||||
self.ensure_one()
|
||||
action = self.env.ref(
|
||||
'stock_card_report.action_report_stock_card_report_html')
|
||||
action = self.env.ref("stock_card_report.action_report_stock_card_report_html")
|
||||
vals = action.read()[0]
|
||||
context = vals.get('context', {})
|
||||
context = vals.get("context", {})
|
||||
if isinstance(context, pycompat.string_types):
|
||||
context = safe_eval(context)
|
||||
model = self.env['report.stock.card.report']
|
||||
model = self.env["report.stock.card.report"]
|
||||
report = model.create(self._prepare_stock_card_report())
|
||||
context['active_id'] = report.id
|
||||
context['active_ids'] = report.ids
|
||||
vals['context'] = context
|
||||
context["active_id"] = report.id
|
||||
context["active_ids"] = report.ids
|
||||
vals["context"] = context
|
||||
return vals
|
||||
|
||||
@api.multi
|
||||
def button_export_pdf(self):
|
||||
self.ensure_one()
|
||||
report_type = 'qweb-pdf'
|
||||
report_type = "qweb-pdf"
|
||||
return self._export(report_type)
|
||||
|
||||
@api.multi
|
||||
def button_export_xlsx(self):
|
||||
self.ensure_one()
|
||||
report_type = 'xlsx'
|
||||
report_type = "xlsx"
|
||||
return self._export(report_type)
|
||||
|
||||
def _prepare_stock_card_report(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'date_from': self.date_from,
|
||||
'date_to': self.date_to or fields.Date.context_today(self),
|
||||
'product_ids': [(6, 0, self.product_ids.ids)],
|
||||
'location_id': self.location_id.id,
|
||||
"date_from": self.date_from,
|
||||
"date_to": self.date_to or fields.Date.context_today(self),
|
||||
"product_ids": [(6, 0, self.product_ids.ids)],
|
||||
"location_id": self.location_id.id,
|
||||
}
|
||||
|
||||
def _export(self, report_type):
|
||||
model = self.env['report.stock.card.report']
|
||||
model = self.env["report.stock.card.report"]
|
||||
report = model.create(self._prepare_stock_card_report())
|
||||
return report.print_report(report_type)
|
||||
|
||||
Reference in New Issue
Block a user