diff --git a/addons/stock/__init__.py b/addons/stock/__init__.py
index f506abac..5138ca84 100644
--- a/addons/stock/__init__.py
+++ b/addons/stock/__init__.py
@@ -5,9 +5,8 @@ from . import controllers
from . import models
from . import report
from . import wizard
-
-
-from flectra import api, SUPERUSER_ID
+from flectra import api
+from flectra.api import Environment, SUPERUSER_ID
# TODO: Apply proper fix & remove in master
@@ -17,3 +16,13 @@ def pre_init_hook(cr):
('model', 'like', '%stock%'),
('module', '=', 'stock')
]).unlink()
+
+
+def post_init_check(cr, registery):
+ env = Environment(cr, SUPERUSER_ID, {})
+ move_obj = env['stock.move']
+ move_ids = move_obj.search([])
+ move_ids.set_move_type()
+ done_moves = move_obj.search([('state', '=', 'done')], order='date')
+ done_moves.check_move_bal_qty()
+ return True
diff --git a/addons/stock/__manifest__.py b/addons/stock/__manifest__.py
index 908cf27f..dee8cbe1 100644
--- a/addons/stock/__manifest__.py
+++ b/addons/stock/__manifest__.py
@@ -86,4 +86,5 @@
'application': True,
'auto_install': False,
'pre_init_hook': 'pre_init_hook',
+ 'post_init_hook': 'post_init_check',
}
diff --git a/addons/stock/models/stock_location.py b/addons/stock/models/stock_location.py
index 5f20bf2e..b569bd56 100644
--- a/addons/stock/models/stock_location.py
+++ b/addons/stock/models/stock_location.py
@@ -25,6 +25,13 @@ class Location(models.Model):
res['barcode'] = res['complete_name']
return res
+ def _should_be_valued(self):
+ self.ensure_one()
+ if self.usage == 'internal' or (
+ self.usage == 'transit' and self.company_id):
+ return True
+ return False
+
name = fields.Char('Location Name', required=True, translate=True)
complete_name = fields.Char("Full Location Name", compute='_compute_complete_name', store=True)
active = fields.Boolean('Active', default=True, help="By unchecking the active field, you may hide a location without deleting it.")
diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py
index 6ac00aa9..3b05bd53 100644
--- a/addons/stock/models/stock_move.py
+++ b/addons/stock/models/stock_move.py
@@ -159,6 +159,9 @@ class StockMove(models.Model):
is_quantity_done_editable = fields.Boolean('Is quantity done editable', compute='_compute_is_quantity_done_editable')
reference = fields.Char(compute='_compute_reference', string="Reference", store=True)
has_move_lines = fields.Boolean(compute='_compute_has_move_lines')
+ out_qty = fields.Float("Out Qty")
+ bal_qty = fields.Float("Balance")
+ move_type = fields.Selection([('in', 'In'), ('out', 'Out')], "Move type")
branch_id = fields.Many2one(
related='location_id.branch_id', store=True,
string='Source Location Branch',
@@ -394,6 +397,17 @@ class StockMove(models.Model):
move.location_id.name, move.location_dest_id.name)))
return res
+ def set_move_type(self):
+ for self in self:
+ if self.picking_type_id and self.picking_type_id.code == 'incoming' or\
+ not self.location_id._should_be_valued() and \
+ self.location_dest_id._should_be_valued():
+ self.move_type = 'in'
+ elif self.picking_type_id and self.picking_type_id.code == 'outgoing' \
+ or self.location_id._should_be_valued() and not \
+ self.location_dest_id._should_be_valued():
+ self.move_type = 'out'
+
@api.model
def create(self, vals):
# TDE CLEANME: why doing this tracking on picking here ? seems weird
@@ -403,6 +417,7 @@ class StockMove(models.Model):
initial_values = {picking.id: {'state': picking.state}}
vals['ordered_qty'] = vals.get('product_uom_qty')
res = super(StockMove, self).create(vals)
+ res.set_move_type()
if perform_tracking:
picking.message_track(picking.fields_get(['state']), initial_values)
return res
@@ -1045,6 +1060,28 @@ class StockMove(models.Model):
break
return extra_move
+ def check_move_bal_qty(self):
+ for move in self:
+ if move.move_type == 'in':
+ move.bal_qty = move.product_uom_qty
+ if move.move_type == 'out':
+ prev_in_moves = self.search([
+ ('product_id', '=', move.product_id.id),
+ ('state', '=', 'done'),
+ ('move_type', '=', 'in'),
+ ('bal_qty', '>', '0'),
+ ], order='date')
+ rem_qty = move.product_uom_qty
+ for pre_move in prev_in_moves:
+ if rem_qty:
+ pre_move.out_qty = move.product_uom_qty
+ if rem_qty > pre_move.bal_qty:
+ rem_qty -= pre_move.bal_qty
+ pre_move.bal_qty = 0
+ else:
+ pre_move.bal_qty -= rem_qty
+ rem_qty -= rem_qty
+
def _action_done(self):
self.filtered(lambda move: move.state == 'draft')._action_confirm() # MRP allows scrapping draft moves
@@ -1105,6 +1142,9 @@ class StockMove(models.Model):
if picking:
picking._create_backorder()
+ #calculate balance quantity & out qty to track the age of each stock
+ moves_todo.check_move_bal_qty()
+
return moves_todo
def unlink(self):
diff --git a/addons/stock/views/stock_move_views.xml b/addons/stock/views/stock_move_views.xml
index 24321c38..db7bea48 100644
--- a/addons/stock/views/stock_move_views.xml
+++ b/addons/stock/views/stock_move_views.xml
@@ -238,6 +238,9 @@
+
+
+
diff --git a/addons/stock_ageing_report/__init__.py b/addons/stock_ageing_report/__init__.py
new file mode 100644
index 00000000..e2c04cfe
--- /dev/null
+++ b/addons/stock_ageing_report/__init__.py
@@ -0,0 +1,5 @@
+# Part of Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import wizard
+from . import report
+from . import models
diff --git a/addons/stock_ageing_report/__manifest__.py b/addons/stock_ageing_report/__manifest__.py
new file mode 100644
index 00000000..3bb1bea8
--- /dev/null
+++ b/addons/stock_ageing_report/__manifest__.py
@@ -0,0 +1,31 @@
+# Part of Flectra. See LICENSE file for full copyright and licensing details.
+
+{
+ 'name': 'Stock Ageing Report',
+ 'version': '1.0',
+ 'category': 'Stock',
+ 'author': 'FlectraHQ',
+ 'website': "https://flectrahq.com",
+ 'depends': ['stock'],
+ 'sequence': 40,
+ 'summary': """Stock Ageing Report to display
+ product's stock by ageing period.""",
+ 'description': """
+Main Features
+-------------
+Stock Ageing Reports.
+An Ageing Analysis Report in Flectra displays the age of the stock in hand.
+This report lists the age-wise break-up of Inventory to point out old stock.
+Flectra gives its users the flexibility to define their own ageing slabs.
+""",
+ 'data': [
+ 'wizard/stock_ageing_wizard_view.xml',
+ 'report/stock_ageing_report_view.xml',
+ 'report/stock_ageing_report_template.xml',
+ ],
+ 'demo': [],
+ 'qweb': [],
+ 'auto_install': False,
+ 'installable': True,
+ 'application': False,
+}
diff --git a/addons/stock_ageing_report/i18n/stock_ageing_report.pot b/addons/stock_ageing_report/i18n/stock_ageing_report.pot
new file mode 100644
index 00000000..7d0b2f08
--- /dev/null
+++ b/addons/stock_ageing_report/i18n/stock_ageing_report.pot
@@ -0,0 +1,189 @@
+# Translation of Flectra Server.
+# This file contains the translation of the following modules:
+# * stock_ageing_report
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Flectra Server 1.2\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2018-05-15 11:07+0000\n"
+"PO-Revision-Date: 2018-05-15 11:07+0000\n"
+"Last-Translator: <>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_report_template
+msgid "Brnach: "
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_report_template
+msgid "Company: "
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_report_template
+msgid "Date: "
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_report_template
+msgid "Location: "
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_report_template
+msgid "Period Length(days): "
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_report_template
+msgid "Product Category: "
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_report_template
+msgid "Warehouse: "
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_branch_id
+msgid "Branch"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_wizard_form_view
+msgid "Cancel"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,help:stock_ageing_report.field_stock_ageing_wizard_date
+msgid "Choose a date to get the inventory ageing report"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_company_id
+msgid "Company"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_create_uid
+msgid "Created by"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_create_date
+msgid "Created on"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_date
+msgid "Date"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_report_stock_ageing_report_stock_ageing_report_template_display_name
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: stock_ageing_report
+#: code:addons/stock_ageing_report/report/stock_ageing_report.py:17
+#, python-format
+msgid "Form content is missing, this report cannot be printed."
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_report_stock_ageing_report_stock_ageing_report_template_id
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_id
+msgid "ID"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model,name:stock_ageing_report.model_stock_location
+msgid "Inventory Locations"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_report_stock_ageing_report_stock_ageing_report_template___last_update
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard___last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_write_uid
+msgid "Last Updated by"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_write_date
+msgid "Last Updated on"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_location_ids
+msgid "Location"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_period_length
+msgid "Period Length (days)"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_wizard_form_view
+msgid "Print"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_product_ids
+msgid "Product"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_product_category_ids
+msgid "Product Category"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_report_template
+msgid "Products"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_wizard_form_view
+msgid "Select following details"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.actions.act_window,name:stock_ageing_report.action_stock_ageing_wizard
+#: model:ir.actions.report,name:stock_ageing_report.action_stock_ageing_report
+#: model:ir.ui.menu,name:stock_ageing_report.stock_ageing_wizard_menu
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_report_template
+msgid "Stock Ageing Report"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.ui.view,arch_db:stock_ageing_report.stock_ageing_report_template
+msgid "Total"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model.fields,field_description:stock_ageing_report.field_stock_ageing_wizard_warehouse_ids
+msgid "Warehouse"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model,name:stock_ageing_report.model_stock_ageing_wizard
+msgid "Wizard that opens the stock ageing"
+msgstr ""
+
+#. module: stock_ageing_report
+#: model:ir.model,name:stock_ageing_report.model_report_stock_ageing_report_stock_ageing_report_template
+msgid "report.stock_ageing_report.stock_ageing_report_template"
+msgstr ""
+
diff --git a/addons/stock_ageing_report/models/__init__.py b/addons/stock_ageing_report/models/__init__.py
new file mode 100644
index 00000000..6bb763b0
--- /dev/null
+++ b/addons/stock_ageing_report/models/__init__.py
@@ -0,0 +1,3 @@
+# Part of Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import stock_location
diff --git a/addons/stock_ageing_report/models/stock_location.py b/addons/stock_ageing_report/models/stock_location.py
new file mode 100644
index 00000000..9618aa46
--- /dev/null
+++ b/addons/stock_ageing_report/models/stock_location.py
@@ -0,0 +1,26 @@
+# Part of Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import models, api
+
+
+class Location(models.Model):
+ _inherit = "stock.location"
+
+ @api.model
+ def name_search(self, name='', args=None, operator='ilike', limit=100):
+ args = args or []
+ domain = []
+
+ if self.env.context.get('warehouse', False):
+ warehouse_ids = self.env['stock.warehouse'].browse(
+ self.env.context['warehouse'][0][2])
+ lot_stock_ids = [wh.lot_stock_id.id for wh in warehouse_ids
+ if wh.lot_stock_id]
+ location_ids = self.env['stock.location'].search(
+ [('location_id', 'child_of', lot_stock_ids),
+ ('usage', '=', 'internal')]).ids
+ location_ids += lot_stock_ids
+ domain = [('id', 'in', location_ids)]
+
+ recs = self.search(domain + args, limit=limit)
+ return recs.name_get()
diff --git a/addons/stock_ageing_report/report/__init__.py b/addons/stock_ageing_report/report/__init__.py
new file mode 100644
index 00000000..12976133
--- /dev/null
+++ b/addons/stock_ageing_report/report/__init__.py
@@ -0,0 +1,3 @@
+# Part of Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import stock_ageing_report
diff --git a/addons/stock_ageing_report/report/stock_ageing_report.py b/addons/stock_ageing_report/report/stock_ageing_report.py
new file mode 100644
index 00000000..8e0fb5c5
--- /dev/null
+++ b/addons/stock_ageing_report/report/stock_ageing_report.py
@@ -0,0 +1,161 @@
+# Part of Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import api, models, _
+from flectra.exceptions import UserError
+from datetime import datetime, timedelta
+from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT
+
+
+class StockAgeingReport(models.AbstractModel):
+ _name = 'report.stock_ageing_report.stock_ageing_report_template'
+
+ @api.model
+ def get_report_values(self, docids, data=None):
+ if not data.get('form') or not self.env.context.get(
+ 'active_model') or not self.env.context.get('active_id'):
+ raise UserError(
+ _("Form content is missing, this report cannot be printed."))
+ report = self.env['ir.actions.report']._get_report_from_name(
+ 'stock_ageing_report.action_stock_ageing_report')
+ get_data = self._get_data(data)
+ return {
+ 'doc_ids': docids,
+ 'doc_model': report.model,
+ 'docs': self,
+ 'data': {
+ 'company': [get_data['company_id']],
+ 'branch': [get_data['branch_id']],
+ 'warehouse': [get_data['warehouse_id']],
+ 'location': [get_data['location_id']],
+ 'product_category': [get_data['product_category_id']],
+ 'product': [get_data['product_id']],
+ 'period_length': [get_data['period_length']],
+ 'date': [get_data['date']],
+ 'period_list': get_data['period_list'],
+ 'product_list': get_data['product_list']
+ }
+ }
+
+ def _get_product_wise_detail(self, product_ids, location_id, date,
+ period_length, branch_id, company_id):
+ product_list = []
+ date_1 = datetime.strftime(date, DATETIME_FORMAT)
+ date_2 = datetime.strftime(
+ date - timedelta(days=period_length), DATETIME_FORMAT)
+ date_3 = datetime.strftime(
+ date - timedelta(days=(period_length * 2)), DATETIME_FORMAT)
+ date_4 = datetime.strftime(
+ date - timedelta(days=(period_length * 3)), DATETIME_FORMAT)
+ date_5 = datetime.strftime(
+ date - timedelta(days=(period_length * 4)), DATETIME_FORMAT)
+ date_period = [date_1, date_2, date_3, date_4, date_5]
+ final_dates = [
+ (date, date_period[date_period.index(date) + 1] if
+ date_period.index(date) < 4 else date)
+ for date in date_period]
+ for product in product_ids:
+ qty_period_list = self.calculate_virtual_qty(
+ product, location_id, branch_id, company_id, final_dates)
+ product_dict = {'product_id': product.name_get()[0][1],
+ 'qty_period_list': qty_period_list,
+ 'qty_available': sum(qty_period_list)}
+ product_list.append(product_dict)
+ return product_list
+
+ def calculate_virtual_qty(self, product, location_id, branch_id,
+ company_id, date_range):
+ product_list = []
+ quant_obj = self.env['stock.quant']
+ move_obj = self.env['stock.move']
+ for date in date_range:
+ domain = []
+ to_date = False
+ from_date = date[0]
+ if date[0] != date[1]:
+ to_date = date[1]
+ domain += [('product_id', '=', product.id)]
+ if product.tracking != 'none':
+ domain += [('location_id', 'in', location_id.ids),
+ ('in_date', '<=', from_date),
+ ('branch_id', '=', branch_id.id),
+ ('company_id', '=', company_id.id)]
+ if to_date:
+ domain += [('in_date', '>', to_date)]
+ virtual_available = sum(
+ [quant.quantity for quant in quant_obj.search(domain)])
+ print ("\n domain", domain)
+ else:
+ domain += ['|', ('location_id', 'in', location_id.ids),
+ ('location_dest_id', 'in', location_id.ids),
+ ('state', '=', 'done'), ('bal_qty', '>', 0),
+ ('date', '<=', from_date),
+ ('branch_dest_id', '=', branch_id.id),
+ ('company_id', '=', company_id.id)]
+ if to_date:
+ domain += [('date', '>', to_date)]
+ virtual_available = sum(
+ [move.bal_qty for move in move_obj.search(domain)])
+ product_list.append(virtual_available)
+ return product_list
+
+ def _get_data(self, data):
+ domain = []
+ company_id = self.env['res.company'].browse(data['form']['company_id'])
+ branch_id = self.env['res.branch'].browse(data['form']['branch_id'])
+ warehouse_id = self.env['stock.warehouse'].browse(
+ data['form']['warehouse_id'])
+ location_id = self.env['stock.location'].browse(
+ data['form']['location_id'])
+ product_category_id = self.env['product.category'].browse(
+ data['form']['product_category_id'])
+ product_id = self.env['product.product'].browse(
+ data['form']['product_id'])
+ if not location_id:
+ location_id = self.env['stock.location'].search([
+ ('company_id', '=', company_id.id),
+ ('usage', '=', 'internal')])
+ period_length = data['form']['period_length']
+ date = datetime.strptime(data['form']['date'], DATETIME_FORMAT)
+
+ if product_id:
+ domain += [('id', 'in', product_id.ids)]
+ elif product_category_id:
+ domain += [('categ_id', 'in', product_category_id.ids),
+ ('type', '=', 'product')]
+ else:
+ domain += [('qty_available', '>', 0)]
+ product_ids = self.env['product.product'].search(domain)
+ product_list = self._get_product_wise_detail(
+ product_ids, location_id, date, period_length, branch_id,
+ company_id)
+ warehouse = location = product_category = ''
+ if warehouse_id:
+ warehouse = ','.join(
+ wh.name_get()[0][1] for wh in
+ warehouse_id) if len(warehouse_id) > 1 else\
+ warehouse_id.name_get()[0][1]
+ if data['form']['location_id']:
+ location = ','.join(loc.name_get()[0][1] for loc in location_id) \
+ if len(location_id) > 1 else location_id.name_get()[0][1] or ''
+ if product_category_id:
+ product_category = ','.join(
+ categ.name_get()[0][1] for categ in product_category_id
+ ) if len(product_category_id) > 1 else\
+ product_category_id.name_get()[0][1] or ''
+ period_list = ['0 - ' + str(period_length),
+ str(period_length) + ' - ' + str(period_length * 2),
+ str(period_length * 2) + ' - ' + str(period_length * 3),
+ str(period_length * 3) + ' - ' + str(period_length * 4),
+ ' + ' + str(period_length * 4)]
+ data['form'].update({
+ 'company_id': company_id,
+ 'branch_id': branch_id,
+ 'warehouse_id': warehouse or '',
+ 'location_id': location or '',
+ 'product_category_id': product_category or '',
+ 'product_id': product_id or '',
+ 'period_length': period_length,
+ 'date': datetime.strftime(date, DATETIME_FORMAT),
+ 'period_list': period_list,
+ 'product_list': product_list})
+ return data['form']
diff --git a/addons/stock_ageing_report/report/stock_ageing_report_template.xml b/addons/stock_ageing_report/report/stock_ageing_report_template.xml
new file mode 100644
index 00000000..e142204b
--- /dev/null
+++ b/addons/stock_ageing_report/report/stock_ageing_report_template.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+ Stock Ageing Report
+
+
+
+
+
+
+ Company: |
+
+
+ |
+ Period Length(days): |
+
+
+ |
+
+
+ Brnach: |
+
+
+ |
+ Date: |
+
+
+ |
+
+
+ Warehouse: |
+
+
+ |
+ Location: |
+
+
+ |
+
+
+ Product Category: |
+
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+ Products |
+
+
+ |
+ Total |
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/addons/stock_ageing_report/report/stock_ageing_report_view.xml b/addons/stock_ageing_report/report/stock_ageing_report_view.xml
new file mode 100644
index 00000000..74b0e4c7
--- /dev/null
+++ b/addons/stock_ageing_report/report/stock_ageing_report_view.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+ Stock Ageing Report Format
+
+ A4
+ 0
+ 0
+ Portrait
+ 40
+ 23
+ 7
+ 7
+
+ 40
+ 90
+
+
+
+ 'stock_ageing'+'-'+(object.name)
+
+
+
\ No newline at end of file
diff --git a/addons/stock_ageing_report/static/description/icon.png b/addons/stock_ageing_report/static/description/icon.png
new file mode 100644
index 00000000..cd4caac2
Binary files /dev/null and b/addons/stock_ageing_report/static/description/icon.png differ
diff --git a/addons/stock_ageing_report/tests/__init__.py b/addons/stock_ageing_report/tests/__init__.py
new file mode 100644
index 00000000..ed0b1b9c
--- /dev/null
+++ b/addons/stock_ageing_report/tests/__init__.py
@@ -0,0 +1,3 @@
+# Part of Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import test_stock_ageing_report
diff --git a/addons/stock_ageing_report/tests/test_stock_ageing_report.py b/addons/stock_ageing_report/tests/test_stock_ageing_report.py
new file mode 100644
index 00000000..1caf0bed
--- /dev/null
+++ b/addons/stock_ageing_report/tests/test_stock_ageing_report.py
@@ -0,0 +1,29 @@
+# Part of Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra.tests.common import TransactionCase
+from datetime import date, timedelta
+
+
+class TestStockAgeingReport(TransactionCase):
+ def setUp(self):
+ super(TestStockAgeingReport, self).setUp()
+ self.location = self.env['stock.location']
+ self.location_barcode = self.env.ref('stock.stock_location_3')
+ self.barcode = self.location_barcode.barcode
+ self.warehouse = self.env["stock.warehouse"]
+
+ def test_20_stock_ageing_report(self):
+ # Print the Stock Ageing Report through the wizard
+ data_dict = {
+ 'company_id': [],
+ 'warehouse_ids': [],
+ 'location_ids': [],
+ 'product_category_ids': [(6, 0, [self.env.ref(
+ 'product.product_category_5').id])],
+ 'product_ids': [(6, 0, [self.env.ref(
+ 'product.product_product_5b').id])],
+ 'period_length': 30,
+ 'date': date.today() - timedelta(days=30),
+ }
+ wizard = self.env['stock.ageing.wizard'].create(data_dict)
+ wizard.with_context(data_dict).print_report()
diff --git a/addons/stock_ageing_report/wizard/__init__.py b/addons/stock_ageing_report/wizard/__init__.py
new file mode 100644
index 00000000..c8c4a5ba
--- /dev/null
+++ b/addons/stock_ageing_report/wizard/__init__.py
@@ -0,0 +1,3 @@
+# Part of Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import stock_ageing_wizard
diff --git a/addons/stock_ageing_report/wizard/stock_ageing_wizard.py b/addons/stock_ageing_report/wizard/stock_ageing_wizard.py
new file mode 100644
index 00000000..21c0710c
--- /dev/null
+++ b/addons/stock_ageing_report/wizard/stock_ageing_wizard.py
@@ -0,0 +1,55 @@
+# Part of Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import api, models, fields
+
+
+class StockAgeingWizard(models.TransientModel):
+
+ _name = 'stock.ageing.wizard'
+ _description = 'Wizard that opens the stock ageing'
+
+ company_id = fields.Many2one('res.company', string="Company",
+ default=lambda self: self.env.user.company_id)
+ branch_id = fields.Many2one('res.branch', string="Branch",
+ default=lambda self:
+ self.env.user.default_branch_id)
+ warehouse_ids = fields.Many2many("stock.warehouse", string="Warehouse")
+ location_ids = fields.Many2many("stock.location", string='Location',
+ domain="[('usage', '=', 'internal')]")
+ product_category_ids = fields.Many2many("product.category",
+ string="Product Category")
+ product_ids = fields.Many2many('product.product', string='Product',
+ domain="[('type', '=', 'product')]")
+ period_length = fields.Integer(string='Period Length (days)', default=30)
+ date = fields.Datetime(string="Date",
+ help="Choose a date to get the inventory ageing "
+ "report",
+ default=fields.Datetime.now())
+
+ @api.multi
+ def print_report(self):
+ """
+ To get the Stock Ageing report and print the report
+ @return : return stock ageing report
+ """
+ datas = {'ids': self._context.get('active_ids', [])}
+ res = self.read(
+ ['company_id', 'branch_id', 'warehouse_ids', 'location_ids',
+ 'product_category_ids', 'product_ids',
+ 'period_length', 'date'])
+ for ageing_dict in res:
+ res = res and res[0] or {}
+ res['company_id'] = ageing_dict['company_id'] and\
+ ageing_dict['company_id'][0] or False
+ res['branch_id'] = ageing_dict['branch_id'] and \
+ ageing_dict['branch_id'][0] or False
+ res['warehouse_id'] = ageing_dict['warehouse_ids']
+ res['location_id'] = ageing_dict['location_ids']
+ res['product_category_id'] = ageing_dict['product_category_ids']
+ res['product_id'] = ageing_dict['product_ids']
+ res['period_length'] = ageing_dict['period_length'] or False
+ res['date'] = ageing_dict['date'] or False
+ datas['form'] = res
+ return self.env.ref(
+ 'stock_ageing_report.action_stock_ageing_report'
+ '').report_action(self, data=datas)
diff --git a/addons/stock_ageing_report/wizard/stock_ageing_wizard_view.xml b/addons/stock_ageing_report/wizard/stock_ageing_wizard_view.xml
new file mode 100644
index 00000000..5da2fe1d
--- /dev/null
+++ b/addons/stock_ageing_report/wizard/stock_ageing_wizard_view.xml
@@ -0,0 +1,50 @@
+
+
+
+
+ Stock Ageing Wizard Form
+ stock.ageing.wizard
+
+
+
+
+
+
+ Stock Ageing Report
+ stock.ageing.wizard
+ form
+ form
+ {'company_id': context.get('company_id', False), 'warehouse_id':
+ context.get('warehouse_ids', False), 'location_id': context.get('location_ids', False),
+ 'product_category_id': context.get('product_category_ids', False), 'product_id':
+ context.get('product_ids', False), 'period_length': context.get('period_length', False), 'date':
+ context.get('date', False)}
+
+ new
+
+
+
+
+