class DetailReport(GridReport): ''' A list report to show operationplans. ''' template = 'output/operationplan.html' title = _("Operation detail report") model = OperationPlan permissions = (("view_operation_report", "Can view operation report"),) frozenColumns = 0 editable = False multiselect = False @ classmethod def basequeryset(reportclass, request, args, kwargs): if args and args[0]: return OperationPlan.objects.filter(operation__exact=args[0]).extra(select={'operation_in': "select name from operation where out_operationplan.operation = operation.name",}) else: return OperationPlan.objects.extra(select={'operation_in': "select name from operation where out_operationplan.operation = operation.name",}) @classmethod def extra_context(reportclass, request, *args, **kwargs): return {'active_tab': 'plandetail'} rows = ( GridFieldInteger('id', title=_('operationplan'), key=True, editable=False), GridFieldText('operation', title=_('operation'), formatter='operation', editable=False), GridFieldNumber('quantity', title=_('quantity'), editable=False), GridFieldDateTime('startdate', title=_('start date'), editable=False), GridFieldDateTime('enddate', title=_('end date'), editable=False), GridFieldBool('locked', title=_('locked'), editable=False), GridFieldNumber('unavailable', title=_('unavailable'), editable=False), GridFieldInteger('owner', title=_('owner'), editable=False), )
class DetailReport(GridReport): ''' A list report to show flowplans. ''' template = 'output/flowplan.html' title = _("Inventory detail report") model = FlowPlan permissions = (('view_inventory_report','Can view inventory report'),) frozenColumns = 0 editable = False multiselect = False @ classmethod def basequeryset(reportclass, request, args, kwargs): if args and args[0]: return FlowPlan.objects.filter(thebuffer__exact=args[0]).extra(select={'operation_in': "select name from operation where out_operationplan.operation = operation.name",}) else: return FlowPlan.objects.extra(select={'operation_in': "select name from operation where out_operationplan.operation = operation.name",}) @classmethod def extra_context(reportclass, request, *args, **kwargs): return {'active_tab': 'plandetail'} rows = ( GridFieldText('thebuffer', title=_('buffer'), key=True, formatter='buffer', editable=False), GridFieldText('operationplan__operation', title=_('operation'), formatter='operation', editable=False), GridFieldNumber('quantity', title=_('quantity'), editable=False), GridFieldDateTime('flowdate', title=_('date'), editable=False), GridFieldNumber('onhand', title=_('onhand'), editable=False), GridFieldBool('operationplan__locked', title=_('locked'), editable=False), GridFieldInteger('operationplan', title=_('operationplan'), editable=False), )
class OperationList(GridReport): ''' A list report to show operations. ''' template = 'input/operationlist.html' title = _("Operation List") basequeryset = Operation.objects.all() model = Operation frozenColumns = 1 rows = ( GridFieldText('name', title=_('name'), key=True, formatter='operation'), GridFieldText('description', title=_('description')), GridFieldText('category', title=_('category')), GridFieldText('subcategory', title=_('subcategory')), GridFieldChoice('type', title=_('type'), choices=Operation.types), GridFieldText('location', title=_('location'), field_name='location__name', formatter='location'), GridFieldDuration('duration', title=_('duration')), GridFieldDuration('duration_per', title=_('duration per unit')), GridFieldDuration('fence', title=_('release fence')), GridFieldDuration('posttime', title=_('post-op time')), GridFieldNumber('sizeminimum', title=_('size minimum')), GridFieldNumber('sizemultiple', title=_('size multiple')), GridFieldNumber('sizemaximum', title=_('size maximum')), GridFieldCurrency('cost', title=_('cost')), GridFieldChoice('search', title=_('search mode'), choices=searchmode), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
class ItemDistributionList(GridReport): ''' A list report to show item distribution. ''' template = 'input/itemdistributionlist.html' title = _("Item Distribution List") basequeryset = ItemDistribution.objects.all() model = ItemDistribution frozenColumns = 1 rows = ( GridFieldInteger('id', title=_('identifier'), key=True, formatter='itemdistribution'), GridFieldText('item', title=_('item'), formatter='item'), GridFieldText('location', title=_('location'), formatter='location'), GridFieldText('origin', title=_('origin'), formatter='location'), GridFieldDuration('leadtime', title=_('lead time')), GridFieldNumber('sizeminimum', title=_('size minimum')), GridFieldNumber('sizemultiple', title=_('size multiple')), GridFieldCurrency('cost', title=_('cost')), GridFieldNumber('priority', title=_('priority')), GridFieldDateTime('effective_start', title=_('effective start')), GridFieldDateTime('effective_end', title=_('effective end')), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
class PurchaseOrderList(GridReport): ''' A list report to show purchase orders. ''' template = 'input/purchaseorderlist.html' title = _("Purchase order List") basequeryset = PurchaseOrder.objects.all() model = PurchaseOrder frozenColumns = 1 rows = ( GridFieldInteger('id', title=_('identifier'), key=True), GridFieldText('reference', title=_('reference')), GridFieldChoice('status', title=_('status'), choices=PurchaseOrder.orderstatus), GridFieldText('item', title=_('item'), field_name='item__name', formatter='item'), GridFieldText('supplier', title=_('supplier'), field_name='supplier__name', formatter='supplier'), GridFieldDateTime('startdate', title=_('start date')), GridFieldDateTime('enddate', title=_('end date')), GridFieldNumber('quantity', title=_('quantity')), GridFieldNumber('criticality', title=_('criticality'), editable=False), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
class DetailReport(GridReport): ''' A list report to show delivery plans for demand. ''' template = 'output/demandplan.html' title = _("Demand plan detail") model = Demand permissions = (("view_demand_report", "Can view demand report"),) frozenColumns = 0 editable = False multiselect = False @ classmethod def basequeryset(reportclass, request, args, kwargs): if args and args[0]: return Demand.objects.filter(item__exact=args[0]) else: return Demand.objects.all() @classmethod def extra_context(reportclass, request, *args, **kwargs): return {'active_tab': 'plandetail'} rows = ( GridFieldText('demand', title=_('demand'), key=True, editable=False, formatter='demand'), GridFieldText('item', title=_('item'), formatter='item', editable=False), GridFieldText('customer', title=_('customer'), formatter='customer', editable=False), GridFieldNumber('quantity', title=_('quantity'), editable=False), GridFieldNumber('planquantity', title=_('planned quantity'), editable=False), GridFieldDateTime('due', title=_('due date'), editable=False), GridFieldDateTime('plandate', title=_('planned date'), editable=False), GridFieldInteger('operationplan', title=_('operationplan'), editable=False), )
class LoadList(GridReport): ''' A list report to show loads. ''' template = 'input/loadlist.html' title = _("Load List") basequeryset = Load.objects.all() model = Load frozenColumns = 1 rows = ( GridFieldInteger('id', title=_('identifier'), key=True, formatter='load'), GridFieldText('operation', title=_('operation'), field_name='operation__name', formatter='operation'), GridFieldText('resource', title=_('resource'), field_name='resource__name', formatter='resource'), GridFieldText('skill', title=_('skill'), formatter='skill'), GridFieldNumber('quantity', title=_('quantity')), GridFieldDateTime('effective_start', title=_('effective start')), GridFieldDateTime('effective_end', title=_('effective end')), GridFieldText('name', title=_('name')), GridFieldText('alternate', title=_('alternate')), GridFieldNumber('priority', title=_('priority')), GridFieldText('setup', title=_('setup')), GridFieldChoice('search', title=_('search mode'), choices=searchmode), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
class FlowList(GridReport): ''' A list report to show flows. ''' template = 'input/flowlist.html' title = _("Flow List") basequeryset = Flow.objects.all() model = Flow frozenColumns = 1 rows = ( GridFieldInteger('id', title=_('identifier'), key=True, formatter='flow'), GridFieldText('operation', title=_('operation'), field_name='operation__name', formatter='operation'), GridFieldText('thebuffer', title=_('buffer'), field_name='thebuffer__name', formatter='buffer'), GridFieldChoice('type', title=_('type'), choices=Flow.types), GridFieldNumber('quantity', title=_('quantity')), GridFieldDateTime('effective_start', title=_('effective start')), GridFieldDateTime('effective_end', title=_('effective end')), GridFieldText('name', title=_('name')), GridFieldText('alternate', title=_('alternate')), GridFieldNumber('priority', title=_('priority')), GridFieldChoice('search', title=_('search mode'), choices=searchmode), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
class DetailReport(GridReport): ''' A list report to show operationplans. ''' template = 'output/operationplan.html' title = _("Operation detail report") model = OperationPlan permissions = (("view_operation_report", "Can view operation report"), ) frozenColumns = 0 editable = False multiselect = False @classmethod def basequeryset(reportclass, request, args, kwargs): if args and args[0]: base = OperationPlan.objects.filter(operation__exact=args[0]) else: base = OperationPlan.objects return base.select_related() \ .extra(select={ 'operation_in': "select name from operation where out_operationplan.operation = operation.name", 'demand': ("select %s(q || ' : ' || d, ', ') from (" "select round(sum(quantity)) as q, demand as d " "from out_demandpegging " "where out_demandpegging.operationplan = out_operationplan.id " "group by demand order by 1 desc, 2) peg" % string_agg()) }) @classmethod def extra_context(reportclass, request, *args, **kwargs): if args and args[0]: request.session['lasttab'] = 'plandetail' return {'active_tab': 'plandetail'} rows = ( GridFieldInteger('id', title=_('operationplan'), key=True, editable=False), GridFieldText('operation', title=_('operation'), editable=False, formatter='detail', extra="role:'input/operation'"), GridFieldNumber('quantity', title=_('quantity'), editable=False), GridFieldText('demand', title=_('demand quantity'), formatter='demanddetail', extra="role:'input/demand'", width=300, editable=False), GridFieldDateTime('startdate', title=_('start date'), editable=False), GridFieldDateTime('enddate', title=_('end date'), editable=False), GridFieldNumber('criticality', title=_('criticality'), editable=False), GridFieldBool('locked', title=_('locked'), editable=False), GridFieldNumber('unavailable', title=_('unavailable'), editable=False), GridFieldInteger('owner', title=_('owner'), editable=False), )
class ItemList(GridReport): title = _("items") basequeryset = Item.objects.all() model = Item frozenColumns = 1 editable = True help_url = "modeling-wizard/master-data/items.html" message_when_empty = Template(""" <h3>Define items</h3> <br> A basic piece of master data is the list of items to plan.<br> End products, intermediate products and raw materials all need to be defined.<br> <br><br> <div role="group" class="btn-group.btn-group-justified"> <a href="{{request.prefix}}/data/input/item/add/" class="btn btn-primary">Create a single item<br>in a form</a> <a href="{{request.prefix}}/wizard/load/production/?currentstep=1" class="btn btn-primary">Wizard to upload items<br>from a spreadsheet</a> </div> <br> """) rows = ( GridFieldHierarchicalText( "name", title=_("name"), key=True, formatter="detail", extra='"role":"input/item"', model=Item, ), GridFieldText("description", title=_("description")), GridFieldText("category", title=_("category"), initially_hidden=True), GridFieldText("subcategory", title=_("subcategory"), initially_hidden=True), GridFieldText( "owner", title=_("owner"), field_name="owner__name", formatter="detail", extra='"role":"input/item"', ), GridFieldCurrency("cost", title=_("cost")), GridFieldNumber("weight", title=_("weight"), initially_hidden=True), GridFieldNumber("volume", title=_("volume"), initially_hidden=True), GridFieldText("uom", title=_("unit of measure"), initially_hidden=True), GridFieldInteger("periodofcover", title=_("period of cover"), initially_hidden=True), GridFieldChoice("type", title=_("type"), choices=Item.types, initially_hidden=True), GridFieldText("source", title=_("source"), initially_hidden=True), GridFieldLastModified("lastmodified"), )
class DetailReport(GridReport): ''' A list report to show loadplans. ''' template = 'output/loadplan.html' title = _("Resource detail report") model = LoadPlan permissions = (("view_resource_report", "Can view resource report"), ) frozenColumns = 0 editable = False multiselect = False @classmethod def basequeryset(reportclass, request, args, kwargs): if args and args[0]: return LoadPlan.objects.filter(theresource__exact=args[0]).select_related() \ .extra(select={'operation_in': "select name from operation where out_operationplan.operation = operation.name"}) else: return LoadPlan.objects.select_related() \ .extra(select={'operation_in': "select name from operation where out_operationplan.operation = operation.name"}) @classmethod def extra_context(reportclass, request, *args, **kwargs): return {'active_tab': 'plandetail'} rows = ( GridFieldText('theresource', title=_('resource'), key=True, formatter='resource', editable=False), GridFieldText('operationplan__operation', title=_('operation'), formatter='operation', editable=False), GridFieldDateTime('startdate', title=_('start date'), editable=False), GridFieldDateTime('enddate', title=_('end date'), editable=False), GridFieldNumber('operationplan__quantity', title=_('operationplan quantity'), editable=False), GridFieldNumber('quantity', title=_('load quantity'), editable=False), GridFieldNumber('operationplan__criticality', title=_('criticality'), editable=False), GridFieldBool('operationplan__locked', title=_('locked'), editable=False), GridFieldNumber('operationplan__unavailable', title=_('unavailable'), editable=False), GridFieldInteger('operationplan', title=_('operationplan'), editable=False), GridFieldText('setup', title=_('setup'), editable=False), )
def getAttributeFields(model, related_name_prefix=None, initially_hidden=False): ''' Return report fields for all attributes of a given model. ''' from freppledb.common.report import GridFieldText, GridFieldBool, GridFieldNumber from freppledb.common.report import GridFieldInteger, GridFieldDate, GridFieldDateTime from freppledb.common.report import GridFieldDuration, GridFieldTime result = [] for field_name, label, fieldtype in _register.get("%s.%s" % (model.__module__, model.__name__), []): if related_name_prefix: field_name = "%s__%s" % (related_name_prefix, field_name) label = "%s - %s" % (related_name_prefix.split('__')[-1], label) else: label = "%s - %s" % (model.__name__, label) if fieldtype == 'string': result.append( GridFieldText(field_name, title=label, initially_hidden=initially_hidden) ) elif fieldtype == 'boolean': result.append( GridFieldBool(field_name, title=label, initially_hidden=initially_hidden) ) elif fieldtype == 'number': result.append( GridFieldNumber(field_name, title=label, initially_hidden=initially_hidden) ) elif fieldtype == 'integer': result.append( GridFieldInteger(field_name, title=label, initially_hidden=initially_hidden) ) elif fieldtype == 'date': result.append( GridFieldDate(field_name, title=label, initially_hidden=initially_hidden) ) elif fieldtype == 'datetime': result.append( GridFieldDateTime(field_name, title=label, initially_hidden=initially_hidden) ) elif fieldtype == 'duration': result.append( GridFieldDuration(field_name, title=label, initially_hidden=initially_hidden) ) elif fieldtype == 'time': result.append( GridFieldTime(field_name, title=label, initially_hidden=initially_hidden) ) else: raise Exception("Invalid attribute type '%s'." % fieldtype) return result
class CalendarBucketList(GridReport): ''' A list report to show calendar buckets. ''' template = 'input/calendarbucketlist.html' title = _("Calendar Bucket List") basequeryset = CalendarBucket.objects.all() model = CalendarBucket frozenColumns = 3 rows = ( GridFieldInteger('id', title=_('identifier'), formatter='calendarbucket'), GridFieldText('calendar', title=_('calendar'), field_name='calendar__name', formatter='calendar'), GridFieldDateTime('startdate', title=_('start date')), GridFieldDateTime('enddate', title=_('end date'), editable=False), GridFieldNumber('value', title=_('value')), GridFieldInteger('priority', title=_('priority')), GridFieldBool('monday', title=_('Monday')), GridFieldBool('tuesday', title=_('Tuesday')), GridFieldBool('wednesday', title=_('Wednesday')), GridFieldBool('thursday', title=_('Thursday')), GridFieldBool('friday', title=_('Friday')), GridFieldBool('saturday', title=_('Saturday')), GridFieldBool('sunday', title=_('Sunday')), GridFieldTime('starttime', title=_('start time')), GridFieldTime('endtime', title=_('end time')), GridFieldText( 'source', title=_('source') ), # Not really right, since the engine doesn't read or store it GridFieldLastModified('lastmodified'), )
class OperationPlanList(GridReport): ''' A list report to show operationplans. ''' template = 'input/operationplanlist.html' title = _("Operationplan List") basequeryset = OperationPlan.objects.all() model = OperationPlan frozenColumns = 1 rows = ( GridFieldInteger('id', title=_('identifier'), key=True), GridFieldText('operation', title=_('operation'), field_name='operation__name', formatter='operation'), GridFieldDateTime('startdate', title=_('start date')), GridFieldDateTime('enddate', title=_('end date')), GridFieldNumber('quantity', title=_('quantity')), GridFieldChoice('status', title=_('status'), choices=OperationPlan.orderstatus), GridFieldInteger('owner', title=_('owner'), extra="formatoptions:{defaultValue:''}"), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
def rows(self, request, *args, **kwargs): cols = [] if args: for c in ( SQLColumn.objects.using(request.database) .filter(report=args[0]) .order_by("sequence") ): if c.format == "number": cols.append(GridFieldNumber(_(c.name), editable=False)) elif c.format == "datetime": cols.append(GridFieldDateTime(_(c.name), editable=False)) elif c.format == "date": cols.append(GridFieldDate(_(c.name), editable=False)) elif c.format == "integer": cols.append(GridFieldInteger(_(c.name), editable=False)) elif c.format == "duration": cols.append(GridFieldDuration(_(c.name), editable=False)) elif c.format == "text": cols.append(GridFieldText(_(c.name), editable=False)) elif c.format == "character": cols.append(GridFieldText(_(c.name), editable=False)) elif c.format == "bool": cols.append(GridFieldBool(_(c.name), editable=False)) elif c.format == "currency": cols.append(GridFieldCurrency(_(c.name), editable=False)) return cols
class BaseReport(GridReport): ''' A list report to show constraints. ''' template = 'output/constraint.html' title = _("Constraint report") basequeryset = Constraint.objects.all() model = Constraint permissions = (("view_constraint_report", "Can view constraint report"),) frozenColumns = 0 editable = False multiselect = False help_url = 'user-guide/user-interface/plan-analysis/constraint-report.html' rows = ( GridFieldInteger('id', title=_('id'), key=True,editable=False, hidden=True), GridFieldText('demand', title=_('demand'), editable=False, formatter='detail', extra="role:'input/demand'"), GridFieldText('entity', title=_('entity'), editable=False, width=80, align='center'), #. Translators: Translation included with Django GridFieldText('name', title=_('name'), editable=False, width=100, align='center'), GridFieldText('owner', title=_('owner'), editable=False, extra='formatter:probfmt'), GridFieldText('description', title=_('description'), editable=False, width=350), GridFieldDateTime('startdate', title=_('start date'), editable=False), GridFieldDateTime('enddate', title=_('end date'), editable=False), GridFieldNumber('weight', title=_('weight'), editable=False), ) @classmethod def extra_context(reportclass, request, *args, **kwargs): if args and args[0]: request.session['lasttab'] = 'constraint' return {'active_tab': 'constraint'}
class Report(GridReport): ''' A list report to show problems. ''' template = 'output/problem.html' title = _("Problem Report") basequeryset = Problem.objects # TODO .extra(select={'forecast': "select name from forecast where out_problem.owner like forecast.name || ' - %%'",}) model = Problem permissions = (("view_problem_report", "Can view problem report"), ) frozenColumns = 0 editable = False multiselect = False rows = ( GridFieldText('entity', title=_('entity'), editable=False, align='center'), # TODO choices=getEntities GridFieldText('name', title=_('name'), editable=False, align='center'), # TODO choices=getNames GridFieldText('owner', title=_('owner'), editable=False, extra='formatter:probfmt'), GridFieldText('description', title=_('description'), editable=False, width=350), GridFieldDateTime('startdate', title=_('start date'), editable=False), GridFieldDateTime('enddate', title=_('end date'), editable=False), GridFieldNumber('weight', title=_('weight'), editable=False), )
class BaseReport(GridReport): ''' A list report to show constraints. ''' template = 'output/constraint.html' title = _("Constraint Report") basequeryset = Constraint.objects.all() model = Constraint permissions = (("view_constraint_report", "Can view constraint report"),) frozenColumns = 0 editable = False multiselect = False rows = ( GridFieldText('demand', title=_('demand'), editable=False, formatter='demand'), GridFieldText('entity', title=_('entity'), editable=False, width=80, align='center'), GridFieldText('name', title=_('name'), editable=False, width=100, align='center'), GridFieldText('owner', title=_('owner'), editable=False, extra='formatter:probfmt'), GridFieldText('description', title=_('description'), editable=False, width=350), GridFieldDateTime('startdate', title=_('start date'), editable=False), GridFieldDateTime('enddate', title=_('end date'), editable=False), GridFieldNumber('weight', title=_('weight'), editable=False), ) @classmethod def extra_context(reportclass, request, *args, **kwargs): return {'active_tab': 'constraint'}
class Report(GridReport): """ A list report to show problems. """ template = "output/problem.html" title = _("Problem report") basequeryset = ( Problem.objects ) # TODO .extra(select={'forecast': "select name from forecast where out_problem.owner like forecast.name || ' - %%'",}) model = Problem permissions = (("view_problem_report", "Can view problem report"),) frozenColumns = 0 editable = False multiselect = False help_url = "user-guide/user-interface/plan-analysis/problem-report.html" rows = ( # . Translators: Translation included with Django GridFieldInteger("id", title=_("id"), key=True, editable=False, hidden=True), GridFieldText( "entity", title=_("entity"), editable=False, align="center" ), # TODO choices=getEntities # . Translators: Translation included with Django GridFieldText( "name", title=_("name"), editable=False, align="center" ), # TODO choices=getNames GridFieldText( "owner", title=_("owner"), editable=False, extra='"formatter":probfmt' ), GridFieldText("description", title=_("description"), editable=False, width=350), GridFieldDateTime("startdate", title=_("start date"), editable=False), GridFieldDateTime("enddate", title=_("end date"), editable=False), GridFieldNumber("weight", title=_("weight"), editable=False), )
class BaseReport(GridReport): """ A list report to show constraints. """ template = "output/constraint.html" title = _("Constraint report") basequeryset = Constraint.objects.all() model = Constraint permissions = (("view_constraint_report", "Can view constraint report"),) frozenColumns = 0 editable = False multiselect = False help_url = "user-interface/plan-analysis/constraint-report.html" detail_post_title = _("constrained demand") detailmodel = None rows = ( GridFieldInteger("id", title=_("id"), key=True, editable=False, hidden=True), GridFieldText( "demand", title=_("demand"), editable=False, formatter="detail", extra='"role":"input/demand"', ), GridFieldText( "entity", title=_("entity"), editable=False, width=80, align="center" ), GridFieldText( "name", title=_("name"), editable=False, width=100, align="center" ), GridFieldText( "owner", title=_("owner"), editable=False, extra='"formatter":probfmt' ), GridFieldText("description", title=_("description"), editable=False, width=350), GridFieldDateTime("startdate", title=_("start date"), editable=False), GridFieldDateTime("enddate", title=_("end date"), editable=False), GridFieldNumber("weight", title=_("weight"), editable=False), ) @classmethod def extra_context(reportclass, request, *args, **kwargs): if args and args[0] and reportclass.detailmodel: request.session["lasttab"] = "constraint" if ( reportclass.detailmodel._meta.model_name == "buffer" and " @ " not in args[0] ): b = Buffer.objects.get(id=args[0]) bufferName = b.item.name + " @ " + b.location.name return { "active_tab": "constraint", "title": force_text(reportclass.detailmodel._meta.verbose_name) + " " + (bufferName if "bufferName" in vars() else args[0]), "post_title": reportclass.detail_post_title, } else: return {"active_tab": "constraint"}
class DetailReport(GridReport): ''' A list report to show OperationPlanResources. ''' template = 'output/loadplan.html' title = _("Resource detail report") model = OperationPlanResource permissions = (("view_resource_report", "Can view resource report"),) frozenColumns = 0 editable = False multiselect = False help_url = 'user-guide/user-interface/plan-analysis/resource-detail-report.html' @ classmethod def basequeryset(reportclass, request, args, kwargs): if args and args[0]: base = OperationPlanResource.objects.filter(resource__exact=args[0]) else: base = OperationPlanResource.objects return base.select_related().extra(select={ 'pegging': "(select string_agg(value || ' : ' || key, ', ') from (select key, value from json_each_text(plan) order by key desc) peg)" }) @classmethod def extra_context(reportclass, request, *args, **kwargs): if args and args[0]: request.session['lasttab'] = 'plandetail' return {'active_tab': 'plandetail'} rows = ( GridFieldInteger('id', title=_('id'), key=True,editable=False, hidden=True), GridFieldText('resource', title=_('resource'), editable=False, formatter='detail', extra="role:'input/resource'"), GridFieldText('operationplan__type', title=_('type'), field_name='operationplan__type', editable=False), GridFieldText('operationplan__operation', title=_('operation'), editable=False, formatter='detail', extra="role:'input/operation'"), GridFieldDateTime('startdate', title=_('start date'), editable=False), GridFieldDateTime('enddate', title=_('end date'), editable=False), GridFieldNumber('operationplan__quantity', title=_('operationplan quantity'), editable=False), GridFieldText('pegging', title=_('demand quantity'), formatter='demanddetail', extra="role:'input/demand'", width=300, editable=False, sortable=False), GridFieldNumber('quantity', title=_('load quantity'), editable=False), GridFieldNumber('operationplan__criticality', title=_('criticality'), editable=False), GridFieldBool('operationplan__status', title=_('status'), editable=False), GridFieldText('setup', title=_('setup'), editable=False), )
class BufferList(GridReport): ''' A list report to show buffers. ''' template = 'input/bufferlist.html' title = _("Buffer List") basequeryset = Buffer.objects.all() model = Buffer frozenColumns = 1 rows = ( GridFieldText('name', title=_('name'), key=True, formatter='buffer'), GridFieldText('description', title=_('description')), GridFieldText('category', title=_('category')), GridFieldText('subcategory', title=_('subcategory')), GridFieldText('location', title=_('location'), field_name='location__name', formatter='location'), GridFieldText('item', title=_('item'), field_name='item__name', formatter='item'), GridFieldNumber('onhand', title=_('onhand')), GridFieldText('owner', title=_('owner'), field_name='owner__name', formatter='buffer'), GridFieldChoice('type', title=_('type'), choices=Buffer.types), GridFieldNumber('minimum', title=_('minimum')), GridFieldText('minimum_calendar', title=_('minimum calendar'), field_name='minimum_calendar__name', formatter='calendar'), GridFieldText('producing', title=_('producing'), field_name='producing__name', formatter='operation'), GridFieldNumber('carrying_cost', title=_('carrying cost')), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
class DemandList(GridReport): ''' A list report to show demands. ''' template = 'input/demandlist.html' title = _("Demand List") basequeryset = Demand.objects.all() model = Demand frozenColumns = 1 rows = ( GridFieldText('name', title=_('name'), key=True, formatter='demand'), GridFieldText('item', title=_('item'), field_name='item__name', formatter='item'), GridFieldText('location', title=_('location'), field_name='location__name', formatter='location'), GridFieldText('customer', title=_('customer'), field_name='customer__name', formatter='customer'), GridFieldText('description', title=_('description')), GridFieldText('category', title=_('category')), GridFieldText('subcategory', title=_('subcategory')), GridFieldDateTime('due', title=_('due')), GridFieldNumber('quantity', title=_('quantity')), GridFieldText('operation', title=_('delivery operation'), formatter='operation'), GridFieldInteger('priority', title=_('priority')), GridFieldText('owner', title=_('owner'), formatter='demand'), GridFieldChoice('status', title=_('status'), choices=Demand.demandstatus), GridFieldDuration('maxlateness', title=_('maximum lateness')), GridFieldNumber('minshipment', title=_('minimum shipment')), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
class ResourceList(GridReport): ''' A list report to show resources. ''' template = 'input/resourcelist.html' title = _("Resource List") basequeryset = Resource.objects.all() model = Resource frozenColumns = 1 rows = ( GridFieldText('name', title=_('name'), key=True, formatter='resource'), GridFieldText('description', title=_('description')), GridFieldText('category', title=_('category')), GridFieldText('subcategory', title=_('subcategory')), GridFieldText('location', title=_('location'), field_name='location__name', formatter='location'), GridFieldText('owner', title=_('owner'), field_name='owner__name', formatter='resource'), GridFieldChoice('type', title=_('type'), choices=Resource.types), GridFieldNumber('maximum', title=_('maximum')), GridFieldText('maximum_calendar', title=_('maximum calendar'), field_name='maximum_calendar__name', formatter='calendar'), GridFieldCurrency('cost', title=_('cost')), GridFieldNumber('maxearly', title=_('maxearly')), GridFieldText('setupmatrix', title=_('setup matrix'), formatter='setupmatrix'), GridFieldText('setup', title=_('setup')), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
class DistributionOrderList(GridReport): ''' A list report to show distribution orders. ''' template = 'input/distributionorderlist.html' title = _("Distribution order List") basequeryset = DistributionOrder.objects.all() model = DistributionOrder frozenColumns = 1 rows = ( GridFieldInteger('id', title=_('identifier'), key=True), GridFieldText('reference', title=_('reference')), GridFieldChoice('status', title=_('status'), choices=DistributionOrder.orderstatus), GridFieldText('item', title=_('item'), field_name='item__name', formatter='item'), GridFieldText('origin', title=_('origin'), field_name='origin__name', formatter='location'), GridFieldText('destination', title=_('destination'), field_name='origin__name', formatter='location'), GridFieldDateTime('startdate', title=_('start date')), GridFieldDateTime('enddate', title=_('end date')), GridFieldNumber('quantity', title=_('quantity')), GridFieldBool('consume_material', title=_('consume material')), GridFieldNumber('criticality', title=_('criticality'), editable=False), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
class CalendarList(GridReport): ''' A list report to show calendars. ''' template = 'input/calendarlist.html' title = _("Calendar List") basequeryset = Calendar.objects.all() model = Calendar frozenColumns = 1 rows = ( GridFieldText('name', title=_('name'), key=True, formatter='calendar'), GridFieldText('description', title=_('description')), GridFieldText('category', title=_('category')), GridFieldText('subcategory', title=_('subcategory')), GridFieldNumber('defaultvalue', title=_('default value')), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
class Report(GridReport): ''' A list report to show problems. ''' template = 'output/problem.html' title = _("Problem report") basequeryset = Problem.objects # TODO .extra(select={'forecast': "select name from forecast where out_problem.owner like forecast.name || ' - %%'",}) model = Problem permissions = (("view_problem_report", "Can view problem report"), ) frozenColumns = 0 editable = False multiselect = False help_url = 'user-guide/user-interface/plan-analysis/problem-report.html' rows = ( #. Translators: Translation included with Django GridFieldInteger('id', title=_('id'), key=True, editable=False, hidden=True), GridFieldText('entity', title=_('entity'), editable=False, align='center'), # TODO choices=getEntities #. Translators: Translation included with Django GridFieldText('name', title=_('name'), editable=False, align='center'), # TODO choices=getNames GridFieldText('owner', title=_('owner'), editable=False, extra='"formatter":probfmt'), GridFieldText('description', title=_('description'), editable=False, width=350), GridFieldDateTime('startdate', title=_('start date'), editable=False), GridFieldDateTime('enddate', title=_('end date'), editable=False), GridFieldNumber('weight', title=_('weight'), editable=False), )
class ResourceSkillList(GridReport): ''' A list report to show resource skills. ''' template = 'input/resourceskilllist.html' title = _("Resource skill List") basequeryset = ResourceSkill.objects.all() model = ResourceSkill frozenColumns = 1 rows = ( GridFieldInteger('id', title=_('identifier'), key=True, formatter='resourceskill'), GridFieldText('resource', title=_('resource'), formatter='resource'), GridFieldText('skill', title=_('skill'), formatter='skill'), GridFieldDateTime('effective_start', title=_('effective start')), GridFieldDateTime('effective_end', title=_('effective end')), GridFieldNumber('priority', title=_('priority')), GridFieldText('source', title=_('source')), GridFieldLastModified('lastmodified'), )
class MyModelList(GridReport): """ This report show an editable grid for your models. You can sort data, filter data, import excel files, export excel files. """ title = _("My models") basequeryset = My_Model.objects.all() model = My_Model frozenColumns = 1 rows = ( GridFieldText( "name", title=_("name"), key=True, formatter="detail", extra='"role":"my_app/my_model"', ), GridFieldText("charfield", title=_("charfield")), GridFieldBoolNullable("booleanfield", title=_("category")), GridFieldNumber("decimalfield", title=_("decimalfield")), GridFieldText("source", title=_("source")), GridFieldLastModified("lastmodified"), )
class OverviewReport(GridPivot): """ A report showing the inventory profile of buffers. """ template = "output/buffer.html" title = _("Inventory report") new_arg_logic = True @classmethod def basequeryset(reportclass, request, *args, **kwargs): if hasattr(request, "basequeryset"): return request.basequeryset item = None location = None batch = None if len(args) and args[0]: if request.path_info.startswith( "/buffer/item/") or request.path_info.startswith( "/detail/input/item/"): item = args[0] else: i_b_l = args[0].split(" @ ") if len(i_b_l) == 1: b = Buffer.objects.values("item", "location").get(id=args[0]) item = b["item"] location = b["location"] elif len(i_b_l) == 2: item = i_b_l[0] location = i_b_l[1] else: item = i_b_l[0] location = i_b_l[2] batch = i_b_l[1] request.basequeryset = OperationPlanMaterial.objects.values( "item", "location", "item__type").filter(( (Q(item__type="make to stock") | Q(item__type__isnull=True))) | (Q(item__type="make to order") & Q(operationplan__batch__isnull=False))) if item: request.basequeryset = request.basequeryset.filter(item=item) if location: request.basequeryset = request.basequeryset.filter( location=location) if batch: request.basequeryset = request.basequeryset.filter( operationplan__batch=batch) request.basequeryset = request.basequeryset.annotate( buffer=RawSQL( "operationplanmaterial.item_id || " "(case when item.type is distinct from 'make to order' then '' else ' @ ' || operationplan.batch end) " "|| ' @ ' || operationplanmaterial.location_id", (), ), opplan_batch=RawSQL( "case when item.type is distinct from 'make to order' then '' else operationplan.batch end", (), ), ).distinct() return request.basequeryset model = OperationPlanMaterial default_sort = (1, "asc", 2, "asc") permissions = (("view_inventory_report", "Can view inventory report"), ) help_url = "user-guide/user-interface/plan-analysis/inventory-report.html" rows = ( GridFieldText("buffer", title=_("buffer"), editable=False, key=True, initially_hidden=True), GridFieldText( "item", title=_("item"), editable=False, field_name="item__name", formatter="detail", extra='"role":"input/item"', ), GridFieldText( "location", title=_("location"), editable=False, field_name="location__name", formatter="detail", extra='"role":"input/location"', ), # Optional fields referencing the item GridFieldText( "item__description", title=format_lazy("{} - {}", _("item"), _("description")), initially_hidden=True, editable=False, ), GridFieldText( "item__type", title=format_lazy("{} - {}", _("item"), _("type")), initially_hidden=True, editable=False, ), GridFieldText( "item__category", title=format_lazy("{} - {}", _("item"), _("category")), initially_hidden=True, editable=False, ), GridFieldText( "item__subcategory", title=format_lazy("{} - {}", _("item"), _("subcategory")), initially_hidden=True, editable=False, ), GridFieldNumber( "item__cost", title=format_lazy("{} - {}", _("item"), _("cost")), initially_hidden=True, editable=False, ), GridFieldText( "item__owner", title=format_lazy("{} - {}", _("item"), _("owner")), field_name="item__owner__name", initially_hidden=True, editable=False, ), GridFieldText( "item__source", title=format_lazy("{} - {}", _("item"), _("source")), initially_hidden=True, editable=False, ), GridFieldLastModified( "item__lastmodified", title=format_lazy("{} - {}", _("item"), _("last modified")), initially_hidden=True, editable=False, ), # Optional fields referencing the location GridFieldText( "location__description", title=format_lazy("{} - {}", _("location"), _("description")), initially_hidden=True, editable=False, ), GridFieldText( "location__category", title=format_lazy("{} - {}", _("location"), _("category")), initially_hidden=True, editable=False, ), GridFieldText( "location__subcategory", title=format_lazy("{} - {}", _("location"), _("subcategory")), initially_hidden=True, editable=False, ), GridFieldText( "location__available", title=format_lazy("{} - {}", _("location"), _("available")), initially_hidden=True, field_name="origin__available__name", formatter="detail", extra='"role":"input/calendar"', editable=False, ), GridFieldText( "location__owner", title=format_lazy("{} - {}", _("location"), _("owner")), initially_hidden=True, field_name="origin__owner__name", formatter="detail", extra='"role":"input/location"', editable=False, ), GridFieldText( "location__source", title=format_lazy("{} - {}", _("location"), _("source")), initially_hidden=True, editable=False, ), GridFieldLastModified( "location__lastmodified", title=format_lazy("{} - {}", _("location"), _("last modified")), initially_hidden=True, editable=False, ), GridFieldText( "batch", title=_("batch"), field_name="opplan_batch", editable=False, initially_hidden=True, ), ) crosses = ( ("startoh", { "title": _("start inventory") }), ("startohdoc", { "title": _("start inventory days of cover") }), ("safetystock", { "title": _("safety stock") }), ("consumed", { "title": _("total consumed") }), ("consumedMO", { "title": _("consumed by MO") }), ("consumedDO", { "title": _("consumed by DO") }), ("consumedSO", { "title": _("consumed by SO") }), ("produced", { "title": _("total produced") }), ("producedMO", { "title": _("produced by MO") }), ("producedDO", { "title": _("produced by DO") }), ("producedPO", { "title": _("produced by PO") }), ("endoh", { "title": _("end inventory") }), ("total_in_progress", { "title": _("total in progress") }), ("work_in_progress_mo", { "title": _("work in progress MO") }), ("on_order_po", { "title": _("on order PO") }), ("in_transit_do", { "title": _("in transit DO") }), ) @classmethod def initialize(reportclass, request): if reportclass._attributes_added != 2: reportclass._attributes_added = 2 reportclass.attr_sql = "" # Adding custom item attributes for f in getAttributeFields(Item, related_name_prefix="item", initially_hidden=True): reportclass.rows += (f, ) reportclass.attr_sql += "item.%s, " % f.name.split("__")[-1] # Adding custom location attributes for f in getAttributeFields(Location, related_name_prefix="location", initially_hidden=True): reportclass.rows += (f, ) reportclass.attr_sql += "location.%s, " % f.name.split( "__")[-1] @classmethod def extra_context(reportclass, request, *args, **kwargs): if not hasattr(request, "basequeryset"): reportclass.basequeryset(request, *args, **kwargs) if args and args[0]: if request.path_info.startswith( "/buffer/item/") or request.path_info.startswith( "/detail/input/item/"): request.session["lasttab"] = "inventory" r = { "title": force_text(Item._meta.verbose_name) + " " + args[0], "post_title": _("inventory"), "active_tab": "inventory", } if request.basequeryset.using(request.database).count() <= 1: r["args"] = args r["mode"] = "table" else: r["args"] = None return r else: request.session["lasttab"] = "plan" index = args[0].find(" @ ") if index == -1: buffer = Buffer.objects.get(id=args[0]) return { "title": force_text(Buffer._meta.verbose_name) + " " + (args[0] if index != -1 else buffer.item.name + " @ " + buffer.location.name), "post_title": _("plan"), "active_tab": "plan", } else: return {} @classmethod def query(reportclass, request, basequery, sortsql="1 asc"): basesql, baseparams = basequery.query.get_compiler( basequery.db).as_sql(with_col_aliases=False) # Execute the actual query query = """ select opplanmat.buffer, item.name item_id, location.name location_id, item.description, item.type, item.category, item.subcategory, item.cost, item.owner_id, item.source, item.lastmodified, location.description, location.category, location.subcategory, location.available_id, location.owner_id, location.source, location.lastmodified, opplanmat.opplan_batch, %s (select jsonb_build_object( 'onhand', onhand, 'flowdate', to_char(flowdate,'YYYY-MM-DD HH24:MI:SS'), 'periodofcover', periodofcover ) from operationplanmaterial inner join operationplan on operationplanmaterial.operationplan_id = operationplan.reference where operationplanmaterial.item_id = item.name and operationplanmaterial.location_id = location.name and (item.type is distinct from 'make to order' or operationplan.batch is not distinct from opplanmat.opplan_batch) and flowdate < greatest(d.startdate,%%s) order by flowdate desc, id desc limit 1) startoh, d.bucket, d.startdate, d.enddate, (select safetystock from ( select 1 as priority, coalesce( (select value from calendarbucket where calendar_id = 'SS for ' || opplanmat.buffer and greatest(d.startdate,%%s) >= startdate and greatest(d.startdate,%%s) < enddate order by priority limit 1), (select defaultvalue from calendar where name = 'SS for ' || opplanmat.buffer) ) as safetystock union all select 2 as priority, coalesce( (select value from calendarbucket where calendar_id = ( select minimum_calendar_id from buffer where item_id = item.name and location_id = location.name and (item.type is distinct from 'make to order' or buffer.batch is not distinct from opplanmat.opplan_batch) ) and greatest(d.startdate,%%s) >= startdate and greatest(d.startdate,%%s) < enddate order by priority limit 1), (select defaultvalue from calendar where name = ( select minimum_calendar_id from buffer where item_id = item.name and location_id = location.name and (item.type is distinct from 'make to order' or buffer.batch is not distinct from opplanmat.opplan_batch) ) ) ) as safetystock union all select 3 as priority, minimum as safetystock from buffer where item_id = item.name and location_id = location.name and (item.type is distinct from 'make to order' or buffer.batch is not distinct from opplanmat.opplan_batch) ) t where t.safetystock is not null order by priority limit 1) safetystock, (select jsonb_build_object( 'work_in_progress_mo', sum(case when (startdate < d.enddate and enddate >= d.enddate) and opm.quantity > 0 and operationplan.type = 'MO' then opm.quantity else 0 end), 'on_order_po', sum(case when (startdate < d.enddate and enddate >= d.enddate) and opm.quantity > 0 and operationplan.type = 'PO' then opm.quantity else 0 end), 'in_transit_do', sum(case when (startdate < d.enddate and enddate >= d.enddate) and opm.quantity > 0 and operationplan.type = 'DO' then opm.quantity else 0 end), 'total_in_progress', sum(case when (startdate < d.enddate and enddate >= d.enddate) and opm.quantity > 0 then opm.quantity else 0 end), 'consumed', sum(case when (opm.flowdate >= greatest(d.startdate,%%s) and opm.flowdate < d.enddate) and opm.quantity < 0 then -opm.quantity else 0 end), 'consumedMO', sum(case when operationplan.type = 'MO' and (opm.flowdate >= greatest(d.startdate,%%s) and opm.flowdate < d.enddate) and opm.quantity < 0 then -opm.quantity else 0 end), 'consumedDO', sum(case when operationplan.type = 'DO' and (opm.flowdate >= greatest(d.startdate,%%s) and opm.flowdate < d.enddate) and opm.quantity < 0 then -opm.quantity else 0 end), 'consumedSO', sum(case when operationplan.type = 'DLVR' and (opm.flowdate >= greatest(d.startdate,%%s) and opm.flowdate < d.enddate) and opm.quantity < 0 then -opm.quantity else 0 end), 'produced', sum(case when (opm.flowdate >= greatest(d.startdate,%%s) and opm.flowdate < d.enddate) and opm.quantity > 0 then opm.quantity else 0 end), 'producedMO', sum(case when operationplan.type = 'MO' and (opm.flowdate >= greatest(d.startdate,%%s) and opm.flowdate < d.enddate) and opm.quantity > 0 then opm.quantity else 0 end), 'producedDO', sum(case when operationplan.type = 'DO' and (opm.flowdate >= greatest(d.startdate,%%s) and opm.flowdate < d.enddate) and opm.quantity > 0 then opm.quantity else 0 end), 'producedPO', sum(case when operationplan.type = 'PO' and (opm.flowdate >= greatest(d.startdate,%%s) and opm.flowdate < d.enddate) and opm.quantity > 0 then opm.quantity else 0 end) ) from operationplanmaterial opm inner join operationplan on operationplan.reference = opm.operationplan_id and ((startdate < d.enddate and enddate >= d.enddate) or (opm.flowdate >= greatest(d.startdate,%%s) and opm.flowdate < d.enddate)) where opm.item_id = item.name and opm.location_id = location.name and (item.type is distinct from 'make to order' or operationplan.batch is not distinct from opplanmat.opplan_batch) ) ongoing from (%s) opplanmat inner join item on item.name = opplanmat.item_id inner join location on location.name = opplanmat.location_id -- Multiply with buckets cross join ( select name as bucket, startdate, enddate from common_bucketdetail where bucket_id = %%s and enddate > %%s and startdate < %%s ) d group by opplanmat.buffer, item.name, location.name, item.description, item.type, item.category, item.subcategory, item.cost, item.owner_id, item.source, item.lastmodified, location.description, location.category, location.subcategory, location.available_id, location.owner_id, location.source, location.lastmodified, opplanmat.opplan_batch, d.bucket, d.startdate, d.enddate order by %s, d.startdate """ % ( reportclass.attr_sql, basesql, sortsql, ) # Build the python result with connections[request.database].chunked_cursor() as cursor_chunked: cursor_chunked.execute( query, ( request.report_startdate, # startoh request.report_startdate, request.report_startdate, request.report_startdate, request.report_startdate, # safetystock ) + (request.report_startdate, ) * 9 + baseparams # ongoing + ( # opplanmat request.report_bucket, request.report_startdate, request.report_enddate, ), # bucket d ) for row in cursor_chunked: numfields = len(row) res = { "buffer": row[0], "item": row[1], "location": row[2], "item__description": row[3], "item__type": row[4], "item__category": row[5], "item__subcategory": row[6], "item__cost": row[7], "item__owner": row[8], "item__source": row[9], "item__lastmodified": row[10], "location__description": row[11], "location__category": row[12], "location__subcategory": row[13], "location__available_id": row[14], "location__owner_id": row[15], "location__source": row[16], "location__lastmodified": row[17], "batch": row[18], "startoh": row[numfields - 6]["onhand"] if row[numfields - 6] else 0, "startohdoc": max( 0, 0 if (row[numfields - 6]["onhand"] if row[numfields - 6] else 0) <= 0 else (999 if row[numfields - 6]["periodofcover"] == 86313600 else (datetime.strptime(row[numfields - 6]["flowdate"], "%Y-%m-%d %H:%M:%S") + timedelta(seconds=row[numfields - 6]["periodofcover"]) - row[numfields - 4]).days if row[numfields - 6]["periodofcover"] else 999), ), "bucket": row[numfields - 5], "startdate": row[numfields - 4], "enddate": row[numfields - 3], "safetystock": row[numfields - 2] or 0, "consumed": row[numfields - 1]["consumed"] or 0, "consumedMO": row[numfields - 1]["consumedMO"] or 0, "consumedDO": row[numfields - 1]["consumedDO"] or 0, "consumedSO": row[numfields - 1]["consumedSO"] or 0, "produced": row[numfields - 1]["produced"] or 0, "producedMO": row[numfields - 1]["producedMO"] or 0, "producedDO": row[numfields - 1]["producedDO"] or 0, "producedPO": row[numfields - 1]["producedPO"] or 0, "total_in_progress": row[numfields - 1]["total_in_progress"] or 0, "work_in_progress_mo": row[numfields - 1]["work_in_progress_mo"] or 0, "on_order_po": row[numfields - 1]["on_order_po"] or 0, "in_transit_do": row[numfields - 1]["in_transit_do"] or 0, "endoh": float(row[numfields - 6]["onhand"] if row[numfields - 6] else 0) + float(row[numfields - 1]["produced"] or 0) - float(row[numfields - 1]["consumed"] or 0), } # Add attribute fields idx = 17 for f in getAttributeFields(Item, related_name_prefix="item"): res[f.field_name] = row[idx] idx += 1 for f in getAttributeFields(Location, related_name_prefix="location"): res[f.field_name] = row[idx] idx += 1 yield res