コード例 #1
0
ファイル: kpi.py プロジェクト: frankxchen/frePPLe
class Report(GridReport):
    title = _("Performance Indicators")
    frozenColumns = 0
    basequeryset = Parameter.objects.all()
    permissions = (("view_kpi_report", "Can view kpi report"), )
    rows = (
        GridFieldText('category',
                      title=_('category'),
                      sortable=False,
                      editable=False,
                      align='center'),
        GridFieldText('name',
                      title=_('name'),
                      sortable=False,
                      editable=False,
                      align='center'),
        GridFieldInteger('value',
                         title=_('value'),
                         sortable=False,
                         editable=False,
                         align='center'),
    )
    default_sort = (1, 'asc')
    filterable = False
    multiselect = False

    @staticmethod
    def query(request, basequery):
        # Execute the query
        cursor = connections[request.database].cursor()
        query = '''
      select 101 as id, 'Problem count' as category, name as name, count(*) as value
      from out_problem
      group by name
      union all
      select 102, 'Problem weight', name, round(sum(weight))
      from out_problem
      group by name
      union all
      select 201, 'Demand', 'Requested', coalesce(round(sum(quantity)),0)
      from out_demand
      union all
      select 202, 'Demand', 'Planned', coalesce(round(sum(planquantity)),0)
      from out_demand
      union all
      select 203, 'Demand', 'Planned late', coalesce(round(sum(planquantity)),0)
      from out_demand
      where plandate > due and plandate is not null
      union all
      select 204, 'Demand', 'Unplanned', coalesce(round(sum(quantity)),0)
      from out_demand
      where planquantity is null
      union all
      select 205, 'Demand', 'Total lateness', coalesce(round(sum(planquantity * %s)),0)
      from out_demand
      where plandate > due and plandate is not null
      union all
      select 301, 'Operation', 'Count', count(*)
      from out_operationplan
      union all
      select 301, 'Operation', 'Quantity', coalesce(round(sum(quantity)),0)
      from out_operationplan
      union all
      select 302, 'Resource', 'Usage', coalesce(round(sum(quantity * %s)),0)
      from out_loadplan
      union all
      select 401, 'Material', 'Produced', coalesce(round(sum(quantity)),0)
      from out_flowplan
      where quantity>0
      union all
      select 402, 'Material', 'Consumed', coalesce(round(sum(-quantity)),0)
      from out_flowplan
      where quantity<0
      order by 1
      ''' % (sql_datediff('plandate',
                          'due'), sql_datediff('enddate', 'startdate'))
        cursor.execute(query)

        # Build the python result
        for row in cursor.fetchall():
            yield {
                'category': row[1],
                'name': row[2],
                'value': row[3],
            }
コード例 #2
0
ファイル: pegging.py プロジェクト: zodioo-team/frepple
class ReportByDemand(GridReport):
    """
    This report shows a simple Gantt chart with the delivery of a sales order.
    """

    template = "output/pegging.html"
    title = _("Demand plan")
    filterable = False
    frozenColumns = 0
    editable = False
    default_sort = None
    hasTimeBuckets = True
    multiselect = False
    heightmargin = 87
    help_url = "user-interface/plan-analysis/demand-gantt-report.html"
    rows = (
        GridFieldText("depth",
                      title=_("depth"),
                      editable=False,
                      sortable=False),
        GridFieldText(
            "operation",
            title=_("operation"),
            editable=False,
            sortable=False,
            key=True,
            formatter="detail",
            extra='"role":"input/operation"',
        ),
        GridFieldText("type",
                      title=_("type"),
                      editable=False,
                      sortable=False,
                      width=100),
        GridFieldText(
            "item",
            title=_("item"),
            editable=False,
            sortable=False,
            initially_hidden=True,
            formatter="detail",
            extra='"role":"input/item"',
        ),
        GridFieldText(
            "item__description",
            title=_("item description"),
            editable=False,
            sortable=False,
            initially_hidden=True,
        ),
        GridFieldText(
            "resource",
            title=_("resource"),
            editable=False,
            sortable=False,
            extra="formatter:reslistfmt",
        ),
        GridFieldNumber(
            "quantity",
            title=_("required quantity"),
            field_name="quantity",
            editable=False,
            sortable=False,
        ),
        GridFieldText(
            "operationplans",
            width=1000,
            extra="formatter:ganttcell",
            editable=False,
            sortable=False,
        ),
        GridFieldText("parent", editable=False, sortable=False, hidden=True),
        GridFieldText("leaf", editable=False, sortable=False, hidden=True),
        GridFieldText("expanded", editable=False, sortable=False, hidden=True),
        GridFieldText("current", editable=False, sortable=False, hidden=True),
        GridFieldText("due", editable=False, sortable=False, hidden=True),
        GridFieldText("showdrilldown",
                      editable=False,
                      sortable=False,
                      hidden=True),
    )

    @classmethod
    def basequeryset(reportclass, request, *args, **kwargs):
        return Demand.objects.filter(name__exact=args[0]).values("name")

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session["lasttab"] = "plan"
            return {
                "active_tab": "plan",
                "title": force_text(Demand._meta.verbose_name) + " " + args[0],
                "post_title": _("plan"),
                "model": Demand,
            }
        else:
            return {}

    @classmethod
    def getBuckets(reportclass, request, *args, **kwargs):
        # Get the earliest and latest operationplan, and the demand due date
        cursor = connections[request.database].cursor()
        cursor.execute(
            """
            with dmd as (
                select
                  due,
                  cast(jsonb_array_elements(plan->'pegging')->>'opplan' as varchar) opplan
                from demand
                where name = %s
                )
            select min(dmd.due), min(startdate), max(enddate)
            from dmd
            inner join operationplan
            on dmd.opplan = operationplan.reference
            and type <> 'STCK'
            """,
            (args[0]),
        )
        x = cursor.fetchone()
        (due, start, end) = x
        if not due:
            # This demand is unplanned
            request.report_startdate = datetime.now().replace(hour=0,
                                                              minute=0,
                                                              second=0,
                                                              microsecond=0)
            request.report_enddate = request.report_startdate + timedelta(
                days=1)
            request.report_bucket = None
            request.report_bucketlist = []
            return
        if not start:
            start = due
        if not end:
            end = due

        # Adjust the horizon
        if due > end:
            end = due
        if due < start:
            start = due
        end += timedelta(days=1)
        start -= timedelta(days=1)
        request.report_startdate = start.replace(hour=0,
                                                 minute=0,
                                                 second=0,
                                                 microsecond=0)
        request.report_enddate = end.replace(hour=0,
                                             minute=0,
                                             second=0,
                                             microsecond=0)
        request.report_bucket = None
        request.report_bucketlist = []

    @classmethod
    def query(reportclass, request, basequery):
        # Build the base query
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)

        # Get current date and horizon
        horizon = (request.report_enddate -
                   request.report_startdate).total_seconds() / 10000
        try:
            current = parse(
                Parameter.objects.using(
                    request.database).get(name="currentdate").value)
        except Exception:
            current = datetime.now()
            current = current.replace(microsecond=0)

        # Collect demand due date, all operationplans and loaded resources
        query = """
          with pegging as (
            select
              min(rownum) as rownum,
              min(due) as due,
              opplan,
              min(lvl) as lvl,
              quantity as required_quantity,
              sum(quantity) as quantity
            from (select
              row_number() over () as rownum, opplan, due, lvl, quantity
            from (select
              due,
              cast(jsonb_array_elements(plan->'pegging')->>'opplan' as varchar) as opplan,
              cast(jsonb_array_elements(plan->'pegging')->>'level' as integer) as lvl,
              cast(jsonb_array_elements(plan->'pegging')->>'quantity' as numeric) as quantity
              from demand
              where name = %s
              ) d1
              ) d2
            group by opplan, quantity
            )
          select
            pegging.due,
            operationplan.name,
            pegging.lvl,
            ops.pegged,
            pegging.rownum,
            operationplan.startdate,
            operationplan.enddate,
            operationplan.quantity,
            operationplan.status,
            array_agg(operationplanresource.resource_id) FILTER (WHERE operationplanresource.resource_id is not null),
            operationplan.type,
            case when operationplan.operation_id is not null then 1 else 0 end as show,
            operationplan.color,
            operationplan.reference,
            operationplan.item_id,
            coalesce(operationplan.location_id, operationplan.destination_id),
            operationplan.supplier_id,
            operationplan.origin_id,
            operationplan.criticality,
            operationplan.demand_id,
            extract(epoch from operationplan.delay),
            pegging.required_quantity,
            operationplan.batch,
            item.description
          from pegging
          inner join operationplan
            on operationplan.reference = pegging.opplan
          left outer join item
            on operationplan.item_id = item.name
          inner join (
            select name,
              min(rownum) as rownum,
              sum(pegging.quantity) as pegged
            from pegging
            inner join operationplan
              on pegging.opplan = operationplan.reference
            group by operationplan.name
            ) ops
          on operationplan.name = ops.name
          left outer join operationplanresource
            on pegging.opplan = operationplanresource.operationplan_id
          group by
            pegging.due, operationplan.name, pegging.lvl, ops.pegged,
            pegging.rownum, operationplan.startdate, operationplan.enddate, operationplan.quantity,
            operationplan.status,
            operationplan.type,
            case when operationplan.operation_id is not null then 1 else 0 end,
            operationplan.color, operationplan.reference, operationplan.item_id,
            item.description,
            coalesce(operationplan.location_id, operationplan.destination_id),
            operationplan.supplier_id, operationplan.origin_id,
            operationplan.criticality, operationplan.demand_id,
            extract(epoch from operationplan.delay), ops.rownum, pegging.required_quantity
          order by ops.rownum, pegging.rownum
          """

        # Build the Python result
        with transaction.atomic(using=request.database):
            with connections[
                    request.database].chunked_cursor() as cursor_chunked:
                cursor_chunked.execute(query, baseparams)
                prevrec = None
                parents = {}
                for rec in cursor_chunked:
                    if not prevrec or rec[1] != prevrec["operation"]:
                        # Return prev operation
                        if prevrec:
                            if prevrec["depth"] < rec[2]:
                                prevrec["leaf"] = "false"
                            yield prevrec
                        # New operation
                        prevrec = {
                            "operation":
                            rec[1],
                            "type":
                            rec[10],
                            "showdrilldown":
                            rec[11],
                            "depth":
                            rec[2],
                            "quantity":
                            str(rec[3]),
                            "item":
                            rec[14],
                            "item__description":
                            rec[23],
                            "due":
                            round(
                                (rec[0] -
                                 request.report_startdate).total_seconds() /
                                horizon,
                                3,
                            ),
                            "current":
                            round(
                                (current -
                                 request.report_startdate).total_seconds() /
                                horizon,
                                3,
                            ),
                            "parent":
                            parents.get(rec[2] - 1, None)
                            if rec[2] and rec[2] >= 1 else None,
                            "leaf":
                            "true",
                            "expanded":
                            "true",
                            "resource":
                            rec[9],
                            "operationplans": [{
                                "operation":
                                rec[1],
                                "quantity":
                                str(rec[7]),
                                "x":
                                round(
                                    (rec[5] - request.report_startdate
                                     ).total_seconds() / horizon,
                                    3,
                                ),
                                "w":
                                round((rec[6] - rec[5]).total_seconds() /
                                      horizon, 3),
                                "startdate":
                                str(rec[5]),
                                "enddate":
                                str(rec[6]),
                                "status":
                                rec[8],
                                "reference":
                                rec[13],
                                "color":
                                round(rec[12])
                                if rec[12] is not None else None,
                                "type":
                                rec[10],
                                "item":
                                rec[14],
                                "location":
                                rec[15],
                                "supplier":
                                rec[16],
                                "origin":
                                rec[17],
                                "criticality":
                                round(rec[18]),
                                "demand":
                                rec[19],
                                "delay":
                                str(rec[20]),
                                "required_quantity":
                                str(rec[21]),
                                "batch":
                                rec[22],
                                "item__description":
                                rec[23],
                            }],
                        }
                        parents[rec[2]] = rec[1]
                    elif rec[4] != prevrec["operationplans"][-1]["reference"]:
                        # Extra operationplan for the operation
                        prevrec["operationplans"].append({
                            "operation":
                            rec[1],
                            "quantity":
                            str(rec[7]),
                            "x":
                            round(
                                (rec[5] -
                                 request.report_startdate).total_seconds() /
                                horizon,
                                3,
                            ),
                            "w":
                            round((rec[6] - rec[5]).total_seconds() / horizon,
                                  3),
                            "startdate":
                            str(rec[5]),
                            "enddate":
                            str(rec[6]),
                            "status":
                            rec[8],
                            "reference":
                            rec[13],
                            "color":
                            round(rec[12]) if rec[12] is not None else None,
                            "type":
                            rec[10],
                            "item":
                            rec[14],
                            "location":
                            rec[15],
                            "supplier":
                            rec[16],
                            "origin":
                            rec[17],
                            "criticality":
                            round(rec[18]),
                            "demand":
                            rec[19],
                            "delay":
                            str(rec[20]),
                            "required_quantity":
                            str(rec[21]),
                            "batch":
                            rec[22],
                            "item__description":
                            rec[23],
                        })
                    elif rec[9] and not rec[9] in prevrec["resource"]:
                        # Extra resource loaded by the operationplan
                        prevrec["resource"].append(rec[9])
                if prevrec:
                    yield prevrec
コード例 #3
0
ファイル: demand.py プロジェクト: marcelomora/frepple
class OverviewReport(GridPivot):
    """
  A report showing the independent demand for each item.
  """

    template = "output/demand.html"
    title = _("Demand report")
    post_title = _("plan")
    basequeryset = Item.objects.all()
    model = Item
    permissions = (("view_demand_report", "Can view demand report"), )
    rows = (
        GridFieldText(
            "item",
            title=_("item"),
            key=True,
            editable=False,
            field_name="name",
            formatter="detail",
            extra='"role":"input/item"',
        ),
        GridFieldText("description",
                      title=_("description"),
                      initially_hidden=True),
        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"',
            initially_hidden=True,
        ),
        GridFieldCurrency("cost", title=_("cost"), initially_hidden=True),
        GridFieldText("source", title=_("source"), initially_hidden=True),
        GridFieldLastModified("lastmodified", initially_hidden=True),
    )
    crosses = (
        ("demand", {
            "title": _("demand")
        }),
        ("supply", {
            "title": _("supply")
        }),
        ("backlog", {
            "title": _("backlog")
        }),
    )
    help_url = "user-guide/user-interface/plan-analysis/demand-report.html"

    @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, initially_hidden=True):
                f.editable = False
                reportclass.rows += (f, )
                reportclass.attr_sql += "parent.%s, " % f.name.split("__")[-1]

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session["lasttab"] = "plan"
            return {
                "title": force_text(Item._meta.verbose_name) + " " + args[0],
                "post_title": _("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)

        # Assure the item hierarchy is up to date
        Item.rebuildHierarchy(database=basequery.db)

        # Execute a query to get the backlog at the start of the horizon
        startbacklogdict = {}
        query = """
      select name, sum(qty) from
        (
        select item.name, sum(demand.quantity) qty from (%s) item
        inner join item child on child.lft between item.lft and item.rght
        inner join demand on demand.item_id = child.name and demand.status in ('open','quote') and due < %%s
        group by item.name
        union all
        select item.name, sum(operationplanmaterial.quantity) qty
        from (%s) item
        inner join item child on child.lft between item.lft and item.rght
        inner join operationplanmaterial on operationplanmaterial.item_id = child.name
        inner join operationplan on operationplan.reference = operationplanmaterial.operationplan_id
          and operationplan.demand_id is not null
          and operationplan.enddate < %%s
        group by item.name
        ) t
        group by name
      """ % (
            basesql,
            basesql,
        )
        with connections[request.database].chunked_cursor() as cursor_chunked:
            cursor_chunked.execute(
                query,
                baseparams + (request.report_startdate, ) + baseparams +
                (request.report_startdate, ),
            )
            for row in cursor_chunked:
                if row[0]:
                    startbacklogdict[row[0]] = float(row[1])

        # Execute the query
        query = """
      select
      parent.name, parent.description, parent.category, parent.subcategory,
      parent.owner_id, parent.cost, parent.source, parent.lastmodified,
      %s
      d.bucket,
      d.startdate,
      d.enddate,
      sum(coalesce((select sum(quantity) from demand
       where demand.item_id = child.name and status in ('open','quote') and due >= greatest(%%s,d.startdate) and due < d.enddate),0)) orders,
      sum(coalesce((select sum(operationplan.quantity) from operationplan
       inner join demand on demand.name = operationplan.demand_id       
       where operationplan.demand_id is not null
       and demand.item_id = child.name
       and operationplan.enddate >= greatest(%%s,d.startdate) and operationplan.enddate < d.enddate),0)) planned
      from (%s) parent
      inner join item child on child.lft between parent.lft and parent.rght
      cross join (
                   select name as bucket, startdate, enddate
                   from common_bucketdetail
                   where bucket_id = %%s and enddate > %%s and startdate < %%s
                   ) d
      group by
        parent.name, parent.description, parent.category, parent.subcategory,
        parent.owner_id, parent.cost, parent.source, parent.lastmodified,
        %s
        d.bucket, d.startdate, d.enddate
      order by %s, d.startdate
    """ % (
            reportclass.attr_sql,
            basesql,
            reportclass.attr_sql,
            sortsql,
        )

        # Build the python result
        with connections[request.database].chunked_cursor() as cursor_chunked:
            cursor_chunked.execute(
                query,
                (request.report_startdate, ) * 2  # orders + planned
                + baseparams  # orders planned
                + (
                    request.report_bucket,
                    request.report_startdate,
                    request.report_enddate,
                ),  # buckets
            )
            previtem = None
            for row in cursor_chunked:
                numfields = len(row)
                if row[0] != previtem:
                    backlog = startbacklogdict.get(row[0], 0)
                    previtem = row[0]
                backlog += float(row[numfields - 2]) - float(
                    row[numfields - 1])
                res = {
                    "item": row[0],
                    "description": row[1],
                    "category": row[2],
                    "subcategory": row[3],
                    "owner": row[4],
                    "cost": row[5],
                    "source": row[6],
                    "lastmodified": row[7],
                    "bucket": row[numfields - 5],
                    "startdate": row[numfields - 4].date(),
                    "enddate": row[numfields - 3].date(),
                    "demand": row[numfields - 2],
                    "supply": row[numfields - 1],
                    "backlog": backlog,
                }
                idx = 8
                for f in getAttributeFields(Item):
                    res[f.field_name] = row[idx]
                    idx += 1
                yield res
コード例 #4
0
class ReportByDemand(GridReport):
    '''
  A list report to show peggings.
  '''
    template = 'output/pegging.html'
    title = _("Demand plan")
    filterable = False
    frozenColumns = 0
    editable = False
    default_sort = None
    hasTimeBuckets = True
    multiselect = False
    heightmargin = 87
    help_url = 'user-guide/user-interface/plan-analysis/demand-gantt-report.html'
    rows = (
        GridFieldText('depth',
                      title=_('depth'),
                      editable=False,
                      sortable=False),
        GridFieldText('operation',
                      title=_('operation'),
                      editable=False,
                      sortable=False,
                      key=True,
                      formatter='detail',
                      extra='"role":"input/operation"'),
        GridFieldText('type',
                      title=_('type'),
                      editable=False,
                      sortable=False,
                      width=100),
        #GridFieldText('buffer', title=_('buffer'), formatter='buffer', editable=False, sortable=False),
        #GridFieldText('item', title=_('item'), formatter='item', editable=False, sortable=False),
        GridFieldText('resource',
                      title=_('resource'),
                      editable=False,
                      sortable=False,
                      extra='formatter:reslistfmt'),
        GridFieldNumber('quantity',
                        title=_('quantity'),
                        editable=False,
                        sortable=False),
        GridFieldText('operationplans',
                      width=1000,
                      extra='formatter:ganttcell',
                      editable=False,
                      sortable=False),
        GridFieldText('parent', editable=False, sortable=False, hidden=True),
        GridFieldText('leaf', editable=False, sortable=False, hidden=True),
        GridFieldText('expanded', editable=False, sortable=False, hidden=True),
        GridFieldText('current', editable=False, sortable=False, hidden=True),
        GridFieldText('due', editable=False, sortable=False, hidden=True),
        GridFieldText('showdrilldown',
                      editable=False,
                      sortable=False,
                      hidden=True),
    )

    @classmethod
    def basequeryset(reportclass, request, *args, **kwargs):
        return Demand.objects.filter(name__exact=args[0]).values('name')

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session['lasttab'] = 'plan'
            return {
                'active_tab': 'plan',
                'title': force_text(Demand._meta.verbose_name) + " " + args[0],
                'post_title': _('plan')
            }
        else:
            return {}

    @classmethod
    def getBuckets(reportclass, request, *args, **kwargs):
        # Get the earliest and latest operationplan, and the demand due date
        cursor = connections[request.database].cursor()
        cursor.execute(
            '''
      with dmd as (
        select
          due,
          cast(jsonb_array_elements(plan->'pegging')->>'opplan' as varchar) opplan
        from demand
        where name = %s
        )
      select min(dmd.due), min(startdate), max(enddate)
      from dmd
      inner join operationplan
      on dmd.opplan = operationplan.reference
      and type <> 'STCK'
      ''', (args[0]))
        x = cursor.fetchone()
        (due, start, end) = x
        if not due:
            # This demand is unplanned
            request.report_startdate = datetime.now().replace(hour=0,
                                                              minute=0,
                                                              second=0,
                                                              microsecond=0)
            request.report_enddate = request.report_startdate + timedelta(
                days=1)
            request.report_bucket = None
            request.report_bucketlist = []
            return
        if not start:
            start = due
        if not end:
            end = due

        # Adjust the horizon
        if due > end:
            end = due
        if due < start:
            start = due
        end += timedelta(days=1)
        start -= timedelta(days=1)
        request.report_startdate = start.replace(hour=0,
                                                 minute=0,
                                                 second=0,
                                                 microsecond=0)
        request.report_enddate = end.replace(hour=0,
                                             minute=0,
                                             second=0,
                                             microsecond=0)
        request.report_bucket = None
        request.report_bucketlist = []

    @classmethod
    def query(reportclass, request, basequery):
        # Build the base query
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)

        # Get current date and horizon
        horizon = (request.report_enddate -
                   request.report_startdate).total_seconds() / 10000
        try:
            current = datetime.strptime(
                Parameter.objects.using(
                    request.database).get(name="currentdate").value,
                "%Y-%m-%d %H:%M:%S")
        except:
            current = datetime.now()
            current = current.replace(microsecond=0)

        # Collect demand due date, all operationplans and loaded resources
        query = '''
      with pegging as (
        select
          min(rownum) as rownum, min(due) as due, opplan, min(lvl) as lvl, sum(quantity) as quantity
        from (select
          row_number() over () as rownum, opplan, due, lvl, quantity
        from (select
          due,
          cast(jsonb_array_elements(plan->'pegging')->>'opplan' as varchar) as opplan,
          cast(jsonb_array_elements(plan->'pegging')->>'level' as integer) as lvl,
          cast(jsonb_array_elements(plan->'pegging')->>'quantity' as numeric) as quantity
          from demand
          where name = %s
          ) d1
          ) d2
        group by opplan
        )
      select
        pegging.due, operationplan.name, pegging.lvl, ops.pegged,
        pegging.rownum, operationplan.startdate, operationplan.enddate, operationplan.quantity,
        operationplan.status, operationplanresource.resource_id, operationplan.type,
        case when operationplan.operation_id is not null then 1 else 0 end as show
      from pegging
      inner join operationplan
        on operationplan.reference = pegging.opplan
      inner join (
        select name,
          min(rownum) as rownum,
          sum(pegging.quantity) as pegged
        from pegging
        inner join operationplan
          on pegging.opplan = operationplan.reference
        group by operationplan.name
        ) ops
      on operationplan.name = ops.name
      left outer join operationplanresource
        on pegging.opplan = operationplanresource.operationplan_id
      order by ops.rownum, pegging.rownum
      '''

        # Build the Python result
        with connections[request.database].chunked_cursor() as cursor_chunked:
            cursor_chunked.execute(query, baseparams)
            prevrec = None
            parents = {}
            for rec in cursor_chunked:
                if not prevrec or rec[1] != prevrec['operation']:
                    # Return prev operation
                    if prevrec:
                        if prevrec['depth'] < rec[2]:
                            prevrec['leaf'] = 'false'
                        yield prevrec
                    # New operation
                    prevrec = {
                        'current':
                        str(current),
                        'operation':
                        rec[1],
                        'type':
                        rec[10],
                        'showdrilldown':
                        rec[11],
                        'depth':
                        rec[2],
                        'quantity':
                        str(rec[3]),
                        'due':
                        round((rec[0] -
                               request.report_startdate).total_seconds() /
                              horizon, 3),
                        'current':
                        round((current -
                               request.report_startdate).total_seconds() /
                              horizon, 3),
                        'parent':
                        parents.get(rec[2] - 1, None)
                        if rec[2] and rec[2] >= 1 else None,
                        'leaf':
                        'true',
                        'expanded':
                        'true',
                        'resource':
                        rec[9] and [
                            rec[9],
                        ] or [],
                        'operationplans': [{
                            'operation':
                            rec[1],
                            'quantity':
                            str(rec[7]),
                            'x':
                            round((rec[5] -
                                   request.report_startdate).total_seconds() /
                                  horizon, 3),
                            'w':
                            round((rec[6] - rec[5]).total_seconds() / horizon,
                                  3),
                            'startdate':
                            str(rec[5]),
                            'enddate':
                            str(rec[6]),
                            'status':
                            rec[8],
                            'id':
                            rec[4]
                        }]
                    }
                    parents[rec[2]] = rec[1]
                elif rec[4] != prevrec['operationplans'][-1]['id']:
                    # Extra operationplan for the operation
                    prevrec['operationplans'].append({
                        'operation':
                        rec[1],
                        'quantity':
                        str(rec[7]),
                        'x':
                        round((rec[5] -
                               request.report_startdate).total_seconds() /
                              horizon, 3),
                        'w':
                        round((rec[6] - rec[5]).total_seconds() / horizon, 3),
                        'startdate':
                        str(rec[5]),
                        'enddate':
                        str(rec[6]),
                        'locked':
                        rec[8],
                        'id':
                        rec[4]
                    })
                elif rec[9] and not rec[9] in prevrec['resource']:
                    # Extra resource loaded by the operationplan
                    prevrec['resource'].append(rec[9])
            if prevrec:
                yield prevrec
コード例 #5
0
class OverviewReport(GridPivot):
    '''
  A report showing the loading of each resource.
  '''
    template = 'output/resource.html'
    title = _('Resource report')
    basequeryset = Resource.objects.all()
    model = Resource
    permissions = (("view_resource_report", "Can view resource report"), )
    editable = False
    help_url = 'user-guide/user-interface/plan-analysis/resource-report.html'

    rows = (
        GridFieldText('resource',
                      title=_('resource'),
                      key=True,
                      editable=False,
                      field_name='name',
                      formatter='detail',
                      extra='"role":"input/resource"'),
        GridFieldText('description',
                      title=_('description'),
                      editable=False,
                      field_name='description',
                      initially_hidden=True),
        GridFieldText('category',
                      title=_('category'),
                      editable=False,
                      field_name='category',
                      initially_hidden=True),
        GridFieldText('subcategory',
                      title=_('subcategory'),
                      editable=False,
                      field_name='subcategory',
                      initially_hidden=True),
        GridFieldText('type',
                      title=_('type'),
                      editable=False,
                      field_name='type',
                      initially_hidden=True),
        GridFieldNumber('maximum',
                        title=_('maximum'),
                        editable=False,
                        field_name='maximum',
                        initially_hidden=True),
        GridFieldText('maximum_calendar',
                      title=_('maximum calendar'),
                      editable=False,
                      field_name='maximum_calendar__name',
                      formatter='detail',
                      extra='"role":"input/calendar"',
                      initially_hidden=True),
        GridFieldCurrency('cost',
                          title=_('cost'),
                          editable=False,
                          field_name='cost',
                          initially_hidden=True),
        GridFieldDuration('maxearly',
                          title=_('maxearly'),
                          editable=False,
                          field_name='maxearly',
                          initially_hidden=True),
        GridFieldText('setupmatrix',
                      title=_('setupmatrix'),
                      editable=False,
                      field_name='setupmatrix__name',
                      formatter='detail',
                      extra='"role":"input/setupmatrix"',
                      initially_hidden=True),
        GridFieldText('setup',
                      title=_('setup'),
                      editable=False,
                      field_name='setup',
                      initially_hidden=True),
        GridFieldText('location__name',
                      title=_('location'),
                      editable=False,
                      field_name='location__name',
                      formatter='detail',
                      extra='"role":"input/location"'),
        GridFieldText('location__description',
                      title=string_concat(_('location'), ' - ',
                                          _('description')),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('location__category',
                      title=string_concat(_('location'), ' - ', _('category')),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('location__subcategory',
                      title=string_concat(_('location'), ' - ',
                                          _('subcategory')),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('location__available',
                      title=string_concat(_('location'), ' - ',
                                          _('available')),
                      editable=False,
                      field_name='location__available__name',
                      formatter='detail',
                      extra='"role":"input/calendar"',
                      initially_hidden=True),
        GridFieldText('avgutil',
                      title=_('utilization %'),
                      field_name='util',
                      formatter='percentage',
                      editable=False,
                      width=100,
                      align='center',
                      search=False),
        GridFieldText('available_calendar',
                      title=_('available calendar'),
                      editable=False,
                      field_name='available__name',
                      formatter='detail',
                      extra='"role":"input/calendar"',
                      initially_hidden=True),
    )
    crosses = (
        ('available', {
            'title': _('available')
        }),
        ('unavailable', {
            'title': _('unavailable')
        }),
        ('setup', {
            'title': _('setup')
        }),
        ('load', {
            'title': _('load')
        }),
        ('utilization', {
            'title': _('utilization %')
        }),
    )

    @classmethod
    def initialize(reportclass, request):
        if reportclass._attributes_added != 2:
            reportclass._attributes_added = 2
            reportclass.attr_sql = ''
            # Adding custom resource attributes
            for f in getAttributeFields(Resource, initially_hidden=True):
                f.editable = False
                reportclass.rows += (f, )
                reportclass.attr_sql += 'res.%s, ' % f.name.split('__')[-1]
            # Adding custom location attributes
            for f in getAttributeFields(Location,
                                        related_name_prefix="location",
                                        initially_hidden=True):
                f.editable = False
                reportclass.rows += (f, )
                reportclass.attr_sql += 'location.%s, ' % f.name.split(
                    '__')[-1]

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session['lasttab'] = 'plan'
            return {
                'units': reportclass.getUnits(request),
                'title':
                force_text(Resource._meta.verbose_name) + " " + args[0],
                'post_title': _('plan'),
            }
        else:
            return {'units': reportclass.getUnits(request)}

    @classmethod
    def getUnits(reportclass, request):
        try:
            units = Parameter.objects.using(
                request.database).get(name="loading_time_units")
            if units.value == 'hours':
                return (1.0, _('hours'))
            elif units.value == 'weeks':
                return (1.0 / 168.0, _('weeks'))
            else:
                return (1.0 / 24.0, _('days'))
        except Exception:
            return (1.0 / 24.0, _('days'))

    @classmethod
    def query(reportclass, request, basequery, sortsql='1 asc'):
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)

        # Get the time units
        units = OverviewReport.getUnits(request)

        # Assure the item hierarchy is up to date
        Resource.rebuildHierarchy(database=basequery.db)

        # Execute the query
        cursor = connections[request.database].cursor()
        query = '''
      select res.name, res.description, res.category, res.subcategory,
        res.type, res.maximum, res.maximum_calendar_id, res.cost, res.maxearly,
        res.setupmatrix_id, res.setup, location.name, location.description,
        location.category, location.subcategory, location.available_id,
        coalesce(max(plan_summary.avg_util),0) as avgutil, res.available_id available_calendar, 
        %s
        d.bucket as col1, d.startdate as col2,
        coalesce(sum(out_resourceplan.available),0) * (case when res.type = 'buckets' then 1 else %f end) as available,
        coalesce(sum(out_resourceplan.unavailable),0) * (case when res.type = 'buckets' then 1 else %f end) as unavailable,
        coalesce(sum(out_resourceplan.load),0) * (case when res.type = 'buckets' then 1 else %f end) as loading,
        coalesce(sum(out_resourceplan.setup),0) * (case when res.type = 'buckets' then 1 else %f end) as setup
      from (%s) res
      left outer join location
        on res.location_id = location.name
      -- 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
      -- Utilization info
      left join out_resourceplan
      on res.name = out_resourceplan.resource
      and d.startdate <= out_resourceplan.startdate
      and d.enddate > out_resourceplan.startdate
      and out_resourceplan.startdate >= '%s'
      and out_resourceplan.startdate < '%s'
      -- Average utilization info
      left join (
          select
            resource,
            ( coalesce(sum(out_resourceplan.load),0) + coalesce(sum(out_resourceplan.setup),0) )
             * 100.0 / coalesce(greatest(sum(out_resourceplan.available), 0.0001),1) as avg_util
          from out_resourceplan
          where out_resourceplan.startdate >= '%s'
          and out_resourceplan.startdate < '%s'
          group by resource
          ) plan_summary
      on res.name = plan_summary.resource
      -- Grouping and sorting
      group by res.name, res.description, res.category, res.subcategory,
        res.type, res.maximum, res.maximum_calendar_id, res.available_id, res.cost, res.maxearly,
        res.setupmatrix_id, res.setup, location.name, location.description,
        location.category, location.subcategory, location.available_id,
        %s d.bucket, d.startdate
      order by %s, d.startdate
      ''' % (reportclass.attr_sql, units[0], units[0], units[0], units[0],
             basesql, request.report_bucket, request.report_startdate,
             request.report_enddate, request.report_startdate,
             request.report_enddate, request.report_startdate,
             request.report_enddate, reportclass.attr_sql, sortsql)
        cursor.execute(query, baseparams)

        # Build the python result
        for row in cursor.fetchall():
            numfields = len(row)
            if row[numfields - 4] != 0:
                util = row[numfields - 2] * 100 / row[numfields - 4]
            else:
                util = 0
            result = {
                'resource': row[0],
                'description': row[1],
                'category': row[2],
                'subcategory': row[3],
                'type': row[4],
                'maximum': row[5],
                'maximum_calendar': row[6],
                'cost': row[7],
                'maxearly': row[8],
                'setupmatrix': row[9],
                'setup': row[10],
                'location__name': row[11],
                'location__description': row[12],
                'location__category': row[13],
                'location__subcategory': row[14],
                'location__available': row[15],
                'avgutil': round(row[16], 2),
                'available_calendar': row[17],
                'bucket': row[numfields - 6],
                'startdate': row[numfields - 5].date(),
                'available': round(row[numfields - 4], 1),
                'unavailable': round(row[numfields - 3], 1),
                'load': round(row[numfields - 2], 1),
                'setup': round(row[numfields - 1], 1),
                'utilization': round(util, 2)
            }
            idx = 17
            for f in getAttributeFields(Resource):
                result[f.field_name] = row[idx]
                idx += 1
            for f in getAttributeFields(Location):
                result[f.field_name] = row[idx]
                idx += 1
            yield result
コード例 #6
0
ファイル: buffer.py プロジェクト: westlyou/frepple
class DetailReport(GridReport):
    '''
  A list report to show OperationPlanMaterial.
  '''
    template = 'input/operationplanreport.html'
    title = _("Inventory detail report")
    model = OperationPlanMaterial
    permissions = (('view_inventory_report', 'Can view inventory report'), )
    frozenColumns = 0
    editable = False
    multiselect = False
    height = 250
    help_url = 'user-guide/user-interface/plan-analysis/inventory-detail-report.html'

    @classmethod
    def basequeryset(reportclass, request, args, kwargs):
        if len(args) and args[0]:
            dlmtr = args[0].find(" @ ")
            base = OperationPlanMaterial.objects.filter(
                item=args[0][:dlmtr], location=args[0][dlmtr + 3:])
        else:
            base = OperationPlanMaterial.objects
        return base.select_related().extra(
            select={
                'pegging':
                "(select string_agg(value || ' : ' || key, ', ') from (select key, value from jsonb_each_text(plan->'pegging') 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',
                'model': Buffer,
                'title': force_text(Buffer._meta.verbose_name) + " " + args[0],
                'post_title': _('plan detail')
            }
        else:
            return {'active_tab': 'plandetail', 'model': None}

    rows = (
        #. Translators: Translation included with Django
        GridFieldInteger('id',
                         title=_('internal id'),
                         key=True,
                         editable=False,
                         hidden=True),
        GridFieldText('item',
                      title=_('item'),
                      field_name='item__name',
                      editable=False,
                      formatter='detail',
                      extra='"role":"input/item"'),
        GridFieldText('location',
                      title=_('location'),
                      field_name='location__name',
                      editable=False,
                      formatter='detail',
                      extra='"role":"input/location"'),
        GridFieldInteger('operationplan__id',
                         title=_('identifier'),
                         editable=False),
        GridFieldText('operationplan__reference',
                      title=_('reference'),
                      editable=False),
        GridFieldText(
            'operationplan__color',
            title=_('inventory status'),
            formatter='color',
            width='125',
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"'),
        GridFieldText('operationplan__type',
                      title=_('type'),
                      field_name='operationplan__type',
                      editable=False),
        GridFieldText('operationplan__name',
                      title=_('operation'),
                      editable=False,
                      field_name='operationplan__name',
                      formatter='detail',
                      extra='"role":"input/operation"'),
        GridFieldText('operationplan__operation__description',
                      title=string_concat(_('operation'), ' - ',
                                          _('description')),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('operationplan__operation__category',
                      title=string_concat(_('operation'), ' - ',
                                          _('category')),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('operationplan__operation__subcategory',
                      title=string_concat(_('operation'), ' - ',
                                          _('subcategory')),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('operationplan__operation__type',
                      title=string_concat(_('operation'), ' - ', _('type')),
                      initially_hidden=True),
        GridFieldDuration('operationplan__operation__duration',
                          title=string_concat(_('operation'), ' - ',
                                              _('duration')),
                          initially_hidden=True),
        GridFieldDuration('operationplan__operation__duration_per',
                          title=string_concat(_('operation'), ' - ',
                                              _('duration per unit')),
                          initially_hidden=True),
        GridFieldDuration('operationplan__operation__fence',
                          title=string_concat(_('operation'), ' - ',
                                              _('release fence')),
                          initially_hidden=True),
        GridFieldDuration('operationplan__operation__posttime',
                          title=string_concat(_('operation'), ' - ',
                                              _('post-op time')),
                          initially_hidden=True),
        GridFieldNumber('operationplan__operation__sizeminimum',
                        title=string_concat(_('operation'), ' - ',
                                            _('size minimum')),
                        initially_hidden=True),
        GridFieldNumber('operationplan__operation__sizemultiple',
                        title=string_concat(_('operation'), ' - ',
                                            _('size multiple')),
                        initially_hidden=True),
        GridFieldNumber('operationplan__operation__sizemaximum',
                        title=string_concat(_('operation'), ' - ',
                                            _('size maximum')),
                        initially_hidden=True),
        GridFieldInteger('operationplan__operation__priority',
                         title=string_concat(_('operation'), ' - ',
                                             _('priority')),
                         initially_hidden=True),
        GridFieldDateTime('operationplan__operation__effective_start',
                          title=string_concat(_('operation'), ' - ',
                                              _('effective start')),
                          initially_hidden=True),
        GridFieldDateTime('operationplan__operation__effective_end',
                          title=string_concat(_('operation'), ' - ',
                                              _('effective end')),
                          initially_hidden=True),
        GridFieldCurrency('operationplan__operation__cost',
                          title=string_concat(_('operation'), ' - ',
                                              _('cost')),
                          initially_hidden=True),
        GridFieldText('operationplan__operation__search',
                      title=string_concat(_('operation'), ' - ',
                                          _('search mode')),
                      initially_hidden=True),
        GridFieldText('operationplan__operation__source',
                      title=string_concat(_('operation'), ' - ', _('source')),
                      initially_hidden=True),
        GridFieldLastModified('operationplan__operation__lastmodified',
                              title=string_concat(_('operation'), ' - ',
                                                  _('last modified')),
                              initially_hidden=True),
        GridFieldDateTime(
            'flowdate',
            title=_('date'),
            editable=False,
            extra=
            '"formatoptions":{"srcformat":"Y-m-d H:i:s","newformat":"Y-m-d H:i:s", "defaultValue":""}, "summaryType":"min"'
        ),
        GridFieldNumber(
            'quantity',
            title=_('quantity'),
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"sum"'),
        GridFieldNumber(
            'onhand',
            title=_('expected onhand'),
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"sum"'),
        GridFieldText('operationplan__status',
                      title=_('status'),
                      editable=False,
                      field_name='operationplan__status'),
        GridFieldNumber(
            'operationplan__criticality',
            title=_('criticality'),
            field_name='operationplan__criticality',
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"'),
        GridFieldDuration(
            'operationplan__delay',
            title=_('delay'),
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"max"'),
        GridFieldNumber(
            'operationplan__quantity',
            title=_('operationplan quantity'),
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"sum"'),
        GridFieldText('pegging',
                      title=_('demands'),
                      formatter='demanddetail',
                      extra='"role":"input/demand"',
                      width=300,
                      editable=False,
                      sortable=False),
        # Optional fields referencing the item
        GridFieldText('item__description',
                      title=string_concat(_('item'), ' - ', _('description')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('item__category',
                      title=string_concat(_('item'), ' - ', _('category')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('item__subcategory',
                      title=string_concat(_('item'), ' - ', _('subcategory')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('item__owner',
                      title=string_concat(_('item'), ' - ', _('owner')),
                      field_name='item__owner__name',
                      initially_hidden=True,
                      editable=False),
        GridFieldText('item__source',
                      title=string_concat(_('item'), ' - ', _('source')),
                      initially_hidden=True,
                      editable=False),
        GridFieldLastModified('item__lastmodified',
                              title=string_concat(_('item'), ' - ',
                                                  _('last modified')),
                              initially_hidden=True,
                              editable=False),
        # Optional fields referencing the location
        GridFieldText('location__description',
                      title=string_concat(_('location'), ' - ',
                                          _('description')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('location__category',
                      title=string_concat(_('location'), ' - ', _('category')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('location__subcategory',
                      title=string_concat(_('location'), ' - ',
                                          _('subcategory')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('location__available',
                      title=string_concat(_('location'), ' - ',
                                          _('available')),
                      initially_hidden=True,
                      field_name='location__available__name',
                      formatter='detail',
                      extra='"role":"input/calendar"',
                      editable=False),
        GridFieldText('location__owner',
                      title=string_concat(_('location'), ' - ', _('owner')),
                      initially_hidden=True,
                      field_name='location__owner__name',
                      formatter='detail',
                      extra='"role":"input/location"',
                      editable=False),
        GridFieldText('location__source',
                      title=string_concat(_('location'), ' - ', _('source')),
                      initially_hidden=True,
                      editable=False),
        GridFieldLastModified('location__lastmodified',
                              title=string_concat(_('location'), ' - ',
                                                  _('last modified')),
                              initially_hidden=True,
                              editable=False),
    )
コード例 #7
0
class OverviewReport(GridPivot):
    """
  A report summarizing all manufacturing orders.
  """

    template = "output/operation.html"
    title = _("Manufacturing order summary")
    model = Operation
    permissions = (("view_operation_report", "Can view operation report"), )
    help_url = (
        "user-guide/user-interface/plan-analysis/manufacturing-order-summary.html"
    )

    rows = (
        GridFieldText(
            "operation",
            title=_("operation"),
            key=True,
            editable=False,
            field_name="name",
            formatter="detail",
            extra='"role":"input/operation"',
        ),
        GridFieldText(
            "location",
            title=_("location"),
            editable=False,
            field_name="location__name",
            formatter="detail",
            extra='"role":"input/location"',
        ),
        # Optional fields on the operation
        GridFieldText(
            "item",
            title=_("item"),
            editable=False,
            field_name="item__name",
            formatter="detail",
            extra='"role":"input/item"',
            initially_hidden=True,
        ),
        GridFieldText("description",
                      title=_("description"),
                      editable=False,
                      initially_hidden=True),
        GridFieldText("category",
                      title=_("category"),
                      editable=False,
                      initially_hidden=True),
        GridFieldText("subcategory",
                      title=_("subcategory"),
                      editable=False,
                      initially_hidden=True),
        GridFieldText("type",
                      title=_("type"),
                      initially_hidden=True,
                      editable=False),
        GridFieldDuration("duration",
                          title=_("duration"),
                          initially_hidden=True,
                          editable=False),
        GridFieldDuration(
            "duration_per",
            title=_("duration per unit"),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldDuration("fence",
                          title=_("release fence"),
                          initially_hidden=True,
                          editable=False),
        GridFieldDuration("posttime",
                          title=_("post-op time"),
                          initially_hidden=True,
                          editable=False),
        GridFieldNumber(
            "sizeminimum",
            title=_("size minimum"),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldNumber(
            "sizemultiple",
            title=_("size multiple"),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldNumber(
            "sizemaximum",
            title=_("size maximum"),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldInteger("priority",
                         title=_("priority"),
                         initially_hidden=True,
                         editable=False),
        GridFieldDateTime(
            "effective_start",
            title=_("effective start"),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldDateTime(
            "effective_end",
            title=_("effective end"),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldCurrency("cost",
                          title=_("cost"),
                          initially_hidden=True,
                          editable=False),
        GridFieldText("search",
                      title=_("search mode"),
                      initially_hidden=True,
                      editable=False),
        GridFieldText("source",
                      title=_("source"),
                      initially_hidden=True,
                      editable=False),
        GridFieldLastModified("lastmodified",
                              initially_hidden=True,
                              editable=False),
        # Optional fields on the location
        GridFieldText(
            "location__description",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("location"), _("description")),
        ),
        GridFieldText(
            "location__category",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("location"), _("category")),
        ),
        GridFieldText(
            "location__subcategory",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("location"), _("subcategory")),
        ),
        GridFieldText(
            "location__available",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("location"), _("available")),
            field_name="location__available__name",
            formatter="detail",
            extra='"role":"input/calendar"',
        ),
        GridFieldLastModified(
            "location__lastmodified",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("location"), _("last modified")),
        ),
        # Optional fields referencing the item
        GridFieldText(
            "item__description",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("description")),
        ),
        GridFieldText(
            "item__category",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("category")),
        ),
        GridFieldText(
            "item__subcategory",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("subcategory")),
        ),
        GridFieldText(
            "item__owner",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("owner")),
            field_name="item__owner__name",
        ),
        GridFieldText(
            "item__source",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("source")),
        ),
        GridFieldLastModified(
            "item__lastmodified",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("last modified")),
        ),
    )

    crosses = (
        ("proposed_start", {
            "title": _("proposed starts")
        }),
        ("total_start", {
            "title": _("total starts")
        }),
        ("proposed_end", {
            "title": _("proposed ends")
        }),
        ("total_end", {
            "title": _("total ends")
        }),
        ("production_proposed", {
            "title": _("proposed production")
        }),
        ("production_total", {
            "title": _("total production")
        }),
    )

    @staticmethod
    def basequeryset(request, *args, **kwargs):
        if args and args[0]:
            request.session["lasttab"] = "plan"
            return Operation.objects.filter(name=args[0])
        else:
            current, start, end = getHorizon(request)
            return Operation.objects.all().extra(
                where=[
                    "exists (select 1 from operationplan where operationplan.operation_id = operation.name and startdate <= %s and enddate >= %s)"
                ],
                params=[end, start],
            )

    @staticmethod
    def extra_context(request, *args, **kwargs):
        if args and args[0]:
            request.session["lasttab"] = "plan"
            return {
                "title":
                force_text(Operation._meta.verbose_name) + " " + args[0],
                "post_title": _("plan"),
            }
        else:
            return {}

    @staticmethod
    def query(request, basequery, sortsql="1 asc"):
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)
        # Build the query
        query = """
      select
        operation.name, location.name, operation.item_id, operation.description,
        operation.category, operation.subcategory, operation.type, operation.duration,
        operation.duration_per, operation.fence, operation.posttime, operation.sizeminimum,
        operation.sizemultiple, operation.sizemaximum, operation.priority, operation.effective_start,
        operation.effective_end, operation.cost, operation.search, operation.source, operation.lastmodified,
        location.description, location.category, location.subcategory, location.available_id,
        location.lastmodified, item.description, item.category, item.subcategory, item.owner_id,
        item.source, item.lastmodified,
        res.bucket, res.startdate, res.enddate,
        res.proposed_start, res.total_start, res.proposed_end, res.total_end, res.proposed_production, res.total_production
      from operation
      left outer join item
      on operation.item_id = item.name
      left outer join location
      on operation.location_id = location.name
      inner join (
        select oper.name as operation_id, d.bucket, d.startdate, d.enddate,
         coalesce(sum(
           case when operationplan.status = 'proposed'
             and d.startdate <= operationplan.startdate and d.enddate > operationplan.startdate
           then operationplan.quantity
           else 0 end
           ), 0) proposed_start,
         coalesce(sum(
           case when d.startdate <= operationplan.startdate and d.enddate > operationplan.startdate
           then operationplan.quantity else 0 end
           ), 0) total_start,
         coalesce(sum(
           case when operationplan.status = 'proposed'
             and d.startdate < operationplan.enddate and d.enddate >= operationplan.enddate
           then operationplan.quantity else 0 end
           ), 0) proposed_end,
         coalesce(sum(
           case when d.startdate < operationplan.enddate and d.enddate >= operationplan.enddate
           then operationplan.quantity else 0 end
           ), 0) total_end,
         coalesce(sum(
           case when operationplan.status = 'proposed' then
             (
             -- Total overlap
             extract (epoch from least(operationplan.enddate, d.enddate) - greatest(operationplan.startdate, d.startdate))
             -- Minus the interruptions
             - coalesce((
                select sum(greatest(0, extract (epoch from
                  least(to_timestamp(value->>1, 'YYYY-MM-DD HH24:MI:SS'), d.enddate)
                  - greatest(to_timestamp(value->>0, 'YYYY-MM-DD HH24:MI:SS'), d.startdate)
                  )))
                from ( select * from jsonb_array_elements(plan->'interruptions')) breaks
                ), 0)
             )
             / greatest(1, extract(epoch from operationplan.enddate - operationplan.startdate) - coalesce((plan#>>'{unavailable}')::numeric, 0))
             * operationplan.quantity
           else 0 end
           ), 0) proposed_production,
         coalesce(sum(
             (
             -- Total overlap
             extract (epoch from least(operationplan.enddate, d.enddate) - greatest(operationplan.startdate, d.startdate))
             -- Minus the interruptions
             - coalesce((
                select sum(greatest(0, extract (epoch from
                  least(to_timestamp(value->>1, 'YYYY-MM-DD HH24:MI:SS'), d.enddate)
                  - greatest(to_timestamp(value->>0, 'YYYY-MM-DD HH24:MI:SS'), d.startdate)
                  )))
                from ( select * from jsonb_array_elements(plan->'interruptions')) breaks
                ), 0)
             )
           / greatest(1, extract(epoch from operationplan.enddate - operationplan.startdate) - coalesce((plan#>>'{unavailable}')::numeric, 0))
           * operationplan.quantity
           ), 0) total_production
        from (%s) oper
        -- 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
        -- Match overlapping operationplans
        left outer join operationplan
          on operationplan.operation_id = oper.name
          and (operationplan.startdate, operationplan.enddate) overlaps (d.startdate, d.enddate)
        group by oper.name, d.bucket, d.startdate, d.enddate
      ) res
      on res.operation_id = operation.name
      order by %s, res.startdate
      """ % (
            basesql,
            request.report_bucket,
            request.report_startdate,
            request.report_enddate,
            sortsql,
        )

        # Convert the SQl results to Python
        with connections[request.database].chunked_cursor() as cursor_chunked:
            cursor_chunked.execute(query, baseparams)
            for row in cursor_chunked:
                yield {
                    "operation": row[0],
                    "location": row[1],
                    "item": row[2],
                    "description": row[3],
                    "category": row[4],
                    "subcategory": row[5],
                    "type": row[6],
                    "duration": row[7],
                    "duration_per": row[8],
                    "fence": row[9],
                    "posttime": row[10],
                    "sizeminimum": row[11],
                    "sizemultiple": row[12],
                    "sizemaximum": row[13],
                    "priority": row[14],
                    "effective_start": row[15],
                    "effective_end": row[16],
                    "cost": row[17],
                    "search": row[18],
                    "source": row[19],
                    "lastmodified": row[20],
                    "location__description": row[21],
                    "location__category": row[22],
                    "location__subcategory": row[23],
                    "location__available": row[24],
                    "location__lastmodified": row[25],
                    "item__description": row[26],
                    "item__category": row[27],
                    "item__subcategory": row[28],
                    "item__owner": row[29],
                    "item__source": row[30],
                    "item__lastmodified": row[31],
                    "bucket": row[32],
                    "startdate": row[33].date(),
                    "enddate": row[34].date(),
                    "proposed_start": row[35],
                    "total_start": row[36],
                    "proposed_end": row[37],
                    "total_end": row[38],
                    "production_proposed": row[39],
                    "production_total": row[40],
                }
コード例 #8
0
class DeliveryOrderList(GridReport):
    template = "input/deliveryorder.html"
    title = _("delivery orders")
    model = DeliveryOrder
    frozenColumns = 0
    editable = True
    multiselect = True
    help_url = "model-reference/delivery-orders.html"
    rows = (
        GridFieldText(
            "reference",
            title=_("reference"),
            key=True,
            formatter="detail",
            extra='role:"input/deliveryorder"',
            editable=not settings.ERP_CONNECTOR,
        ),
        GridFieldText("batch",
                      title=_("batch"),
                      editable="true",
                      initially_hidden=True),
        GridFieldText(
            "demand",
            title=_("demand"),
            field_name="demand__name",
            formatter="detail",
            extra='"role":"input/demand"',
        ),
        GridFieldText(
            "item",
            title=_("item"),
            field_name="item__name",
            formatter="detail",
            extra='"role":"input/item"',
        ),
        GridFieldText(
            "customer",
            title=_("customer"),
            field_name="demand__customer__name",
            formatter="detail",
            extra='"role":"input/customer"',
        ),
        GridFieldText(
            "location",
            title=_("location"),
            field_name="location__name",
            formatter="detail",
            extra='"role":"input/location"',
        ),
        GridFieldNumber("quantity", title=_("quantity")),
        GridFieldNumber("demand__quantity",
                        title=_("demand quantity"),
                        editable=False),
        GridFieldDateTime("startdate", title=_("start date")),
        GridFieldDateTime(
            "enddate",
            title=_("end date"),
            extra=GridFieldDateTime.extra + ',"cellattr":enddatecellattr',
        ),
        GridFieldDateTime("due",
                          field_name="demand__due",
                          title=_("due date"),
                          editable=False),
        GridFieldChoice(
            "status",
            title=_("status"),
            choices=OperationPlan.orderstatus,
            editable=not settings.ERP_CONNECTOR,
        ),
        GridFieldDuration(
            "delay",
            title=_("delay"),
            editable=False,
            initially_hidden=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"max"',
        ),
        # Optional fields referencing the item
        GridFieldText(
            "item__type",
            title=format_lazy("{} - {}", _("item"), _("type")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "item__description",
            title=format_lazy("{} - {}", _("item"), _("description")),
            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,
        ),
        GridFieldCurrency(
            "item__cost",
            title=format_lazy("{} - {}", _("item"), _("cost")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldNumber(
            "item__volume",
            title=format_lazy("{} - {}", _("item"), _("volume")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldNumber(
            "item__weight",
            title=format_lazy("{} - {}", _("item"), _("weight")),
            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="location__available__name",
            formatter="detail",
            extra='"role":"input/calendar"',
            editable=False,
        ),
        GridFieldText(
            "location__owner",
            title=format_lazy("{} - {}", _("location"), _("owner")),
            initially_hidden=True,
            field_name="location__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,
        ),
        # Optional fields referencing the customer
        GridFieldText(
            "demand__customer__description",
            title=format_lazy("{} - {}", _("customer"), _("description")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "demand__customer__category",
            title=format_lazy("{} - {}", _("customer"), _("category")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "demand__customer__subcategory",
            title=format_lazy("{} - {}", _("customer"), _("subcategory")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "demand__customer__owner",
            title=format_lazy("{} - {}", _("customer"), _("owner")),
            initially_hidden=True,
            field_name="supplier__owner__name",
            formatter="detail",
            extra='"role":"input/supplier"',
            editable=False,
        ),
        GridFieldText(
            "demand__customer__source",
            title=format_lazy("{} - {}", _("customer"), _("source")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldLastModified(
            "demand__customer__lastmodified",
            title=format_lazy("{} - {}", _("customer"), _("last modified")),
            initially_hidden=True,
            editable=False,
        ),
    )

    @classmethod
    def basequeryset(reportclass, request, *args, **kwargs):

        q = DeliveryOrder.objects.all()

        # special keyword superop used for search field of operationplan
        if "parentreference" in request.GET:
            parentreference = request.GET["parentreference"]
            q = q.filter(reference=parentreference)

        if args and args[0]:
            path = request.path.split("/")[4]
            if path == "consumed":
                return q.filter(
                    item__name=args[0],
                    location__name=args[1],
                    enddate__gte=args[2],
                    enddate__lt=args[3],
                )
            else:
                try:
                    itm = Item.objects.all().using(
                        request.database).get(name=args[0])
                    lft = itm.lft
                    rght = itm.rght
                except Item.DoesNotExist:
                    lft = 1
                    rght = 1
                q = q.filter(item__lft__gte=lft, item__rght__lte=rght)

        return q

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session["lasttab"] = "deliveryorders"
            path = request.path.split("/")[4]
            if path == "consumed":
                return {
                    "active_tab":
                    "deliveryorders",
                    "model":
                    Item,
                    "title":
                    force_text(Item._meta.verbose_name) + " " + args[0],
                    "post_title":
                    force_text(
                        _("delivered from %(loc)s between %(date1)s and %(date2)s"
                          ) % {
                              "loc": args[1],
                              "date1": args[2],
                              "date2": args[3]
                          }),
                }
            else:
                return {
                    "active_tab": "deliveryorders",
                    "title":
                    force_text(Item._meta.verbose_name) + " " + args[0],
                    "post_title": _("delivery orders"),
                }
        else:
            return {"active_tab": "deliveryorders"}

    @classmethod
    def initialize(reportclass, request):
        if reportclass._attributes_added != 2:
            reportclass._attributes_added = 2
            for f in getAttributeFields(DeliveryOrder):
                reportclass.rows += (f, )
            for f in getAttributeFields(Item, related_name_prefix="item"):
                f.editable = False
                f.initially_hidden = True
                reportclass.rows += (f, )
            for f in getAttributeFields(Location,
                                        related_name_prefix="location"):
                f.editable = False
                f.initially_hidden = True
                reportclass.rows += (f, )
            for f in getAttributeFields(
                    Customer, related_name_prefix="demand__customer"):
                f.editable = False
                f.initially_hidden = True
                reportclass.rows += (f, )
コード例 #9
0
class ItemSupplierList(GridReport):
    title = _("item suppliers")
    basequeryset = ItemSupplier.objects.all()
    model = ItemSupplier
    frozenColumns = 1
    help_url = "modeling-wizard/purchasing/item-suppliers.html"
    message_when_empty = Template(
        """
        <h3>Define item suppliers</h3>
        <br>
        This table defines which items can be procured from which supplier.<br>
        <br><br>
        <div role="group" class="btn-group.btn-group-justified">
        <a href="{{request.prefix}}/data/input/itemsupplier/add/" class="btn btn-primary">Create a single item supplier<br>in a form</a>
        <a href="{{request.prefix}}/wizard/load/production/?currentstep=4" class="btn btn-primary">Wizard to upload item suppliers<br>from a spreadsheet</a>
        </div>
        <br>
        """
    )

    rows = (
        GridFieldInteger(
            "id",
            title=_("identifier"),
            key=True,
            formatter="detail",
            extra='"role":"input/itemsupplier"',
            initially_hidden=True,
        ),
        GridFieldHierarchicalText(
            "item",
            title=_("item"),
            field_name="item__name",
            formatter="detail",
            extra='"role":"input/item"',
            model=Item,
        ),
        GridFieldHierarchicalText(
            "location",
            title=_("location"),
            field_name="location__name",
            formatter="detail",
            extra='"role":"input/location"',
            model=Location,
        ),
        GridFieldText(
            "supplier",
            title=_("supplier"),
            field_name="supplier__name",
            formatter="detail",
            extra='"role":"input/supplier"',
        ),
        GridFieldDuration("leadtime", title=_("lead time")),
        GridFieldNumber("sizeminimum", title=_("size minimum")),
        GridFieldNumber("sizemultiple", title=_("size multiple")),
        GridFieldNumber("sizemaximum", title=_("size maximum"), initially_hidden=True),
        GridFieldCurrency("cost", title=_("cost")),
        GridFieldInteger("priority", title=_("priority")),
        GridFieldDuration("fence", title=_("fence"), initially_hidden=True),
        GridFieldDateTime(
            "effective_start", title=_("effective start"), initially_hidden=True
        ),
        GridFieldDateTime(
            "effective_end", title=_("effective end"), initially_hidden=True
        ),
        GridFieldText(
            "resource",
            title=_("resource"),
            field_name="resource__name",
            formatter="detail",
            extra='"role":"input/resource"',
            initially_hidden=True,
        ),
        GridFieldNumber(
            "resource_qty", title=_("resource quantity"), initially_hidden=True
        ),
        GridFieldText("source", title=_("source"), initially_hidden=True),
        GridFieldLastModified("lastmodified"),
        # Optional fields referencing the item
        GridFieldText(
            "item__type",
            title=format_lazy("{} - {}", _("item"), _("type")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "item__description",
            title=format_lazy("{} - {}", _("item"), _("description")),
            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,
        ),
        GridFieldCurrency(
            "item__cost",
            title=format_lazy("{} - {}", _("item"), _("cost")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldNumber(
            "item__volume",
            title=format_lazy("{} - {}", _("item"), _("volume")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldNumber(
            "item__weight",
            title=format_lazy("{} - {}", _("item"), _("weight")),
            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="location__available__name",
            formatter="detail",
            extra='"role":"input/calendar"',
            editable=False,
        ),
        GridFieldText(
            "location__owner",
            title=format_lazy("{} - {}", _("location"), _("owner")),
            initially_hidden=True,
            field_name="location__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,
        ),
        # Optional fields referencing the supplier
        GridFieldText(
            "supplier__description",
            title=format_lazy("{} - {}", _("supplier"), _("description")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "supplier__category",
            title=format_lazy("{} - {}", _("supplier"), _("category")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "supplier__subcategory",
            title=format_lazy("{} - {}", _("supplier"), _("subcategory")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "supplier__available",
            title=format_lazy("{} - {}", _("supplier"), _("available")),
            field_name="supplier__available__name",
            formatter="detail",
            extra='"role":"input/calendar"',
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "supplier__source",
            title=format_lazy("{} - {}", _("supplier"), _("source")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldLastModified(
            "supplier__lastmodified",
            title=format_lazy("{} - {}", _("supplier"), _("last modified")),
            initially_hidden=True,
            editable=False,
        ),
    )

    @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]
コード例 #10
0
class TaskReport(GridReport):
  '''
  A list report to review the history of actions.
  '''
  template = 'execute/execute.html'
  title = _('Task status')
  basequeryset = Task.objects.all().extra(select={
    'duration': "case when status in ('Done', '100%%') then finished::timestamp(0) - started::timestamp(0) end"
      })
  model = Task
  frozenColumns = 0
  multiselect = False
  editable = False
  height = 150
  default_sort = (0, 'desc')
  help_url = 'user-guide/user-interface/execute.html'

  rows = (
    GridFieldInteger('id', title=_('identifier'), key=True),
    #. Translators: Translation included with Django
    GridFieldText('name', title=_('name'), editable=False, align='center'),
    GridFieldDateTime('submitted', title=_('submitted'), editable=False, align='center'),
    GridFieldDateTime('started', title=_('started'), editable=False, align='center'),
    GridFieldDateTime('finished', title=_('finished'), editable=False, align='center'),
    GridFieldText('status', title=_('status'), editable=False, align='center', extra="formatter:status"),
    GridFieldText('logfile', title=_('log file'), width=80, editable=False, align='center', extra="formatter:logbutton"),
    GridFieldText('message', title=_('message'), editable=False, width=500, formatter='longstring'),
    GridFieldText('arguments', title=_('arguments'), editable=False),
    #. Translators: Translation included with Django
    GridFieldText('user', title=_('user'), field_name='user__username', editable=False, align='center'),
    GridFieldDuration('duration', title=_('duration'), search=False, editable=False, align='center'),
    GridFieldBool('cancelable', title="cancelable", hidden=True)
    )


  @classmethod
  def extra_context(reportclass, request, *args, **kwargs):
    # Loop over all accordion of all apps and directories
    accordions = set()
    accord = ''
    for commandname, appname in get_commands().items():
      try:
        accord = getattr(import_module('%s.management.commands.%s' % (appname, commandname)), 'Command')
        if accord.index >= 0 and getattr(accord, 'getHTML', None):
          accordions.add(accord)
      except Exception:
        pass  # Silently ignore failures

    accordions = sorted(accordions, key=operator.attrgetter('index'))

    # Send to template
    return {'commandlist': accordions}


  @classmethod
  def query(reportclass, request, basequery, sortsql='1 asc'):
    logfileslist = set([x for x in os.listdir(settings.FREPPLE_LOGDIR) if x.endswith('.log')])
    for rec in basequery:
      yield {
        'id': rec.id,
        'name': rec.name,
        'submitted': rec.submitted,
        'started': rec.started,
        'finished': rec.finished,
        'status': rec.status,
        'logfile': rec.logfile if rec.logfile in logfileslist else None,
        'message': rec.message,
        'arguments': rec.arguments,
        'user__username': rec.user.username if rec.user else None,
        'duration': rec.duration,
        'cancelable': rec.processid is not None or rec.status == 'Waiting'
        }


  @classmethod
  def extraJSON(reportclass, request):
    try:
      lastCompletedTask = Task.objects.all().using(request.database).filter(status='Done').order_by('-id').only('id')[0]
      return '"lastcompleted":%d,\n' % lastCompletedTask.id
    except:
      return '"lastcompleted":0,\n'
コード例 #11
0
class DemandList(GridReport):
    template = "input/demand.html"
    title = _("sales orders")
    model = Demand
    frozenColumns = 1
    help_url = "modeling-wizard/master-data/sales-orders.html"
    message_when_empty = Template("""
        <h3>Define sales orders</h3>
        <br>
        The sales orders table contains all the orders placed by your customers.<br><br>
        Orders in the status "open" are still be delivered and will be planned.<br><br>
        <br><br>
        <div role="group" class="btn-group.btn-group-justified">
        <a href="{{request.prefix}}/data/input/demand/add/" class="btn btn-primary">Create a single sales order<br>in a form</a>
        <a href="{{request.prefix}}/wizard/load/production/?currentstep=2" class="btn btn-primary">Wizard to upload sale orders<br>from a spreadsheet</a>
        </div>
        <br>
        """)

    @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]
            # Adding custom customer attributes
            for f in getAttributeFields(Customer,
                                        related_name_prefix="customer",
                                        initially_hidden=True):
                reportclass.rows += (f, )
                reportclass.attr_sql += "customer.%s, " % f.name.split(
                    "__")[-1]
            # Adding custom demand attributes
            for f in getAttributeFields(Demand, initially_hidden=True):
                reportclass.rows += (f, )
                reportclass.attr_sql += "demand.%s, " % f.name.split("__")[-1]

    @classmethod
    def basequeryset(reportclass, request, *args, **kwargs):

        q = Demand.objects.all()

        if "item" in request.GET:
            item = Item.objects.using(
                request.database).get(name__exact=unquote(request.GET["item"]))
            q = q.filter(item__lft__gte=item.lft, item__lft__lt=item.rght)
        if "location" in request.GET:
            location = Location.objects.using(request.database).get(
                name__exact=unquote(request.GET["location"]))
            q = q.filter(location__lft__gte=location.lft,
                         location__lft__lt=location.rght)
        if "customer" in request.GET:
            customer = Customer.objects.using(request.database).get(
                name__exact=unquote(request.GET["customer"]))
            q = q.filter(customer_lft__gte=customer.lft,
                         customer_lft__lt=customer.rght)
        if "status_in" in request.GET:
            status = unquote(request.GET["status_in"])
            q = q.filter(status__in=status.split(","))

        return q.annotate(
            plannedshort=RawSQL("quantity - plannedquantity", []))

    rows = (
        GridFieldText(
            "name",
            title=_("name"),
            key=True,
            formatter="detail",
            extra='"role":"input/demand"',
        ),
        GridFieldHierarchicalText(
            "item",
            title=_("item"),
            field_name="item__name",
            formatter="detail",
            extra='"role":"input/item"',
            model=Item,
        ),
        GridFieldText("batch", title=_("batch"), initially_hidden=True),
        GridFieldHierarchicalText(
            "location",
            title=_("location"),
            field_name="location__name",
            formatter="detail",
            extra='"role":"input/location"',
            model=Location,
        ),
        GridFieldHierarchicalText(
            "customer",
            title=_("customer"),
            field_name="customer__name",
            formatter="detail",
            extra='"role":"input/customer"',
            model=Customer,
        ),
        GridFieldChoice("status",
                        title=_("status"),
                        choices=Demand.demandstatus),
        GridFieldNumber("quantity", title=_("quantity")),
        GridFieldDateTime("due", title=_("due")),
        GridFieldDuration("delay",
                          title=_("delay"),
                          editable=False,
                          extra='"formatter":delayfmt'),
        GridFieldNumber(
            "plannedquantity",
            title=_("planned quantity"),
            editable=False,
            extra=
            '"formatoptions":{"defaultValue":""}, "cellattr":plannedquantitycellattr',
        ),
        GridFieldNumber(
            "plannedshort",
            title=_("quantity planned short"),
            editable=False,
            extra=
            '"formatoptions":{"defaultValue":""}, "cellattr":plannedquantitycellattr',
        ),
        GridFieldDateTime("deliverydate",
                          title=_("delivery date"),
                          editable=False),
        GridFieldText("description",
                      title=_("description"),
                      initially_hidden=True),
        GridFieldText("category", title=_("category"), initially_hidden=True),
        GridFieldText("subcategory",
                      title=_("subcategory"),
                      initially_hidden=True),
        GridFieldText(
            "operation",
            title=_("delivery operation"),
            field_name="operation__name",
            formatter="detail",
            extra='"role":"input/operation"',
            initially_hidden=True,
        ),
        GridFieldInteger("priority", title=_("priority")),
        GridFieldText(
            "owner",
            title=_("owner"),
            field_name="owner__name",
            formatter="detail",
            extra='"role":"input/demand"',
            initially_hidden=True,
        ),
        GridFieldDuration("maxlateness",
                          title=_("maximum lateness"),
                          initially_hidden=True),
        GridFieldNumber("minshipment",
                        title=_("minimum shipment"),
                        initially_hidden=True),
        GridFieldText("batch",
                      title=_("batch"),
                      field_name="batch",
                      initially_hidden=True),
        GridFieldText("source", title=_("source"), initially_hidden=True),
        GridFieldLastModified("lastmodified"),
        # Optional fields referencing the item
        GridFieldText(
            "item__type",
            title=format_lazy("{} - {}", _("item"), _("type")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "item__description",
            title=format_lazy("{} - {}", _("item"), _("description")),
            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,
        ),
        GridFieldText(
            "item__owner",
            title=format_lazy("{} - {}", _("item"), _("owner")),
            field_name="item__owner__name",
            initially_hidden=True,
            editable=False,
            formatter="detail",
            extra='"role":"input/item"',
        ),
        GridFieldCurrency(
            "item__cost",
            title=format_lazy("{} - {}", _("item"), _("cost")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldNumber(
            "item__volume",
            title=format_lazy("{} - {}", _("item"), _("volume")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldNumber(
            "item__weight",
            title=format_lazy("{} - {}", _("item"), _("weight")),
            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="location__available__name",
            formatter="detail",
            extra='"role":"input/calendar"',
            editable=False,
        ),
        GridFieldText(
            "location__owner",
            title=format_lazy("{} - {}", _("location"), _("owner")),
            initially_hidden=True,
            field_name="location__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,
        ),
        # Optional fields referencing the customer
        GridFieldText(
            "customer__description",
            title=format_lazy("{} - {}", _("customer"), _("description")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "customer__category",
            title=format_lazy("{} - {}", _("customer"), _("category")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "customer__subcategory",
            title=format_lazy("{} - {}", _("customer"), _("subcategory")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "customer__owner",
            title=format_lazy("{} - {}", _("customer"), _("owner")),
            initially_hidden=True,
            field_name="customer__owner__name",
            formatter="detail",
            extra='"role":"input/customer"',
            editable=False,
        ),
        GridFieldText(
            "customer__source",
            title=format_lazy("{} - {}", _("customer"), _("source")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldLastModified(
            "customer__lastmodified",
            title=format_lazy("{} - {}", _("customer"), _("last modified")),
            initially_hidden=True,
            editable=False,
        ),
    )

    if settings.ERP_CONNECTOR:
        actions = [{
            "name":
            "erp_incr_export",
            "label":
            format_lazy("export to {erp}", erp=settings.ERP_CONNECTOR),
            "function":
            "ERPconnection.SODepExport(jQuery('#grid'),'SO')",
        }]
    else:
        actions = [
            {
                "name":
                "inquiry",
                "label":
                format_lazy(_("change status to {status}"),
                            status=_("inquiry")),
                "function":
                "grid.setStatus('inquiry')",
            },
            {
                "name":
                "quote",
                "label":
                format_lazy(_("change status to {status}"), status=_("quote")),
                "function":
                "grid.setStatus('quote')",
            },
            {
                "name":
                "open",
                "label":
                format_lazy(_("change status to {status}"), status=_("open")),
                "function":
                "grid.setStatus('open')",
            },
            {
                "name":
                "closed",
                "label":
                format_lazy(_("change status to {status}"),
                            status=_("closed")),
                "function":
                "grid.setStatus('closed')",
            },
            {
                "name":
                "canceled",
                "label":
                format_lazy(_("change status to {status}"),
                            status=_("canceled")),
                "function":
                "grid.setStatus('canceled')",
            },
        ]
コード例 #12
0
ファイル: buffer.py プロジェクト: pvl/frePPLe
class OverviewReport(GridPivot):
    '''
  A report showing the inventory profile of buffers.
  '''
    template = 'output/buffer.html'
    title = _('Inventory report')
    basequeryset = Buffer.objects.only('name', 'item__name', 'location__name',
                                       'lft', 'rght', 'onhand')
    model = Buffer
    permissions = (('view_inventory_report', 'Can view inventory report'), )
    rows = (
        GridFieldText('buffer',
                      title=_('buffer'),
                      key=True,
                      editable=False,
                      field_name='name',
                      formatter='detail',
                      extra="role:'input/buffer'"),
        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'"),
    )
    crosses = (
        ('startoh', {
            'title': _('start inventory')
        }),
        ('produced', {
            'title': _('produced')
        }),
        ('consumed', {
            'title': _('consumed')
        }),
        ('endoh', {
            'title': _('end inventory')
        }),
    )

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session['lasttab'] = 'plan'
            return {
                'title':
                capfirst(
                    force_text(Buffer._meta.verbose_name) + " " + args[0]),
                'post_title':
                ': ' + capfirst(force_text(_('plan'))),
            }
        else:
            return {}

    @staticmethod
    def query(request, basequery, sortsql='1 asc'):
        cursor = connections[request.database].cursor()
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)

        # Assure the item hierarchy is up to date
        Buffer.rebuildHierarchy(database=basequery.db)

        # Execute a query  to get the onhand value at the start of our horizon
        startohdict = {}
        query = '''
      select buffers.name, sum(oh.onhand)
      from (%s) buffers
      inner join buffer
      on buffer.lft between buffers.lft and buffers.rght
      inner join (
      select out_flowplan.thebuffer as thebuffer, out_flowplan.onhand as onhand
      from out_flowplan,
        (select thebuffer, max(id) as id
         from out_flowplan
         where flowdate < '%s'
         group by thebuffer
        ) maxid
      where maxid.thebuffer = out_flowplan.thebuffer
      and maxid.id = out_flowplan.id
      ) oh
      on oh.thebuffer = buffer.name
      group by buffers.name
      ''' % (basesql, request.report_startdate)
        cursor.execute(query, baseparams)
        for row in cursor.fetchall():
            startohdict[row[0]] = float(row[1])

        # Execute the actual query
        query = '''
      select buf.name as row1, buf.item_id as row2, buf.location_id as row3,
             d.bucket as col1, d.startdate as col2, d.enddate as col3,
             coalesce(sum(%s),0.0) as consumed,
             coalesce(-sum(%s),0.0) as produced
        from (%s) buf
        -- 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
        -- Include child buffers
        inner join buffer
        on buffer.lft between buf.lft and buf.rght
        -- Consumed and produced quantities
        left join out_flowplan
        on buffer.name = out_flowplan.thebuffer
        and d.startdate <= out_flowplan.flowdate
        and d.enddate > out_flowplan.flowdate
        and out_flowplan.flowdate >= '%s'
        and out_flowplan.flowdate < '%s'
        -- Grouping and sorting
        group by buf.name, buf.item_id, buf.location_id, buf.onhand, d.bucket, d.startdate, d.enddate
        order by %s, d.startdate
      ''' % (sql_max('out_flowplan.quantity',
                     '0.0'), sql_min('out_flowplan.quantity',
                                     '0.0'), basesql, request.report_bucket,
             request.report_startdate, request.report_enddate,
             request.report_startdate, request.report_enddate, sortsql)
        cursor.execute(query, baseparams)

        # Build the python result
        prevbuf = None
        for row in cursor.fetchall():
            if row[0] != prevbuf:
                prevbuf = row[0]
                startoh = startohdict.get(prevbuf, 0)
                endoh = startoh + float(row[6] - row[7])
            else:
                startoh = endoh
                endoh += float(row[6] - row[7])
            yield {
                'buffer': row[0],
                'item': row[1],
                'location': row[2],
                'bucket': row[3],
                'startdate': python_date(row[4]),
                'enddate': python_date(row[5]),
                'startoh': round(startoh, 1),
                'produced': round(row[6], 1),
                'consumed': round(row[7], 1),
                'endoh': round(endoh, 1),
            }
コード例 #13
0
ファイル: buffer.py プロジェクト: pvl/frePPLe
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]:
            base = FlowPlan.objects.filter(thebuffer__exact=args[0])
        else:
            base = FlowPlan.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_flowplan.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 = (
        GridFieldText('thebuffer',
                      title=_('buffer'),
                      key=True,
                      editable=False,
                      formatter='detail',
                      extra="role:'input/buffer'"),
        GridFieldText('operationplan__operation',
                      title=_('operation'),
                      editable=False,
                      formatter='detail',
                      extra="role:'input/operation'"),
        GridFieldNumber('quantity', title=_('quantity'), editable=False),
        GridFieldDateTime('flowdate', title=_('date'), editable=False),
        GridFieldNumber('onhand', title=_('onhand'), editable=False),
        GridFieldNumber('operationplan__criticality',
                        title=_('criticality'),
                        editable=False),
        GridFieldBool('operationplan__locked',
                      title=_('locked'),
                      editable=False),
        GridFieldNumber('operationplan__quantity',
                        title=_('operationplan quantity'),
                        editable=False),
        GridFieldText('demand',
                      title=_('demand quantity'),
                      formatter='demanddetail',
                      width=300,
                      editable=False),
        GridFieldInteger('operationplan',
                         title=_('operationplan'),
                         editable=False),
    )
コード例 #14
0
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, editable 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,
                              editable=editable))
        elif fieldtype == 'boolean':
            result.append(
                GridFieldBool(field_name,
                              title=label,
                              initially_hidden=initially_hidden,
                              editable=editable))
        elif fieldtype == 'number':
            result.append(
                GridFieldNumber(field_name,
                                title=label,
                                initially_hidden=initially_hidden,
                                editable=editable))
        elif fieldtype == 'integer':
            result.append(
                GridFieldInteger(field_name,
                                 title=label,
                                 initially_hidden=initially_hidden,
                                 editable=editable))
        elif fieldtype == 'date':
            result.append(
                GridFieldDate(field_name,
                              title=label,
                              initially_hidden=initially_hidden,
                              editable=editable))
        elif fieldtype == 'datetime':
            result.append(
                GridFieldDateTime(field_name,
                                  title=label,
                                  initially_hidden=initially_hidden,
                                  editable=editable))
        elif fieldtype == 'duration':
            result.append(
                GridFieldDuration(field_name,
                                  title=label,
                                  initially_hidden=initially_hidden,
                                  editable=editable))
        elif fieldtype == 'time':
            result.append(
                GridFieldTime(field_name,
                              title=label,
                              initially_hidden=initially_hidden,
                              editable=editable))
        else:
            raise Exception("Invalid attribute type '%s'." % fieldtype)
    return result
コード例 #15
0
class PurchaseReport(GridPivot):
    '''
  A report summarizing all purchase orders.
  '''
    template = 'output/purchase_order_summary.html'
    title = _('Purchase order summary')
    model = PurchaseOrder
    help_url = 'user-guide/user-interface/plan-analysis/purchase-order-summary.html'

    rows = (
        GridFieldText('key',
                      key=True,
                      search=False,
                      initially_hidden=True,
                      hidden=True,
                      field_name="item__name",
                      editable=False),
        GridFieldText('item',
                      title=_('item'),
                      editable=False,
                      field_name='item__name',
                      formatter='detail',
                      extra='"role":"input/item"'),
        GridFieldText('item__description',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('description'))),
        GridFieldText('item__category',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('category'))),
        GridFieldText('item__subcategory',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('subcategory'))),
        GridFieldCurrency('item__cost',
                          initially_hidden=True,
                          editable=False,
                          title=string_concat(_('item'), ' - ', _('cost')),
                          field_name='item__cost'),
        GridFieldText('item__owner',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('owner')),
                      field_name='item__owner__name'),
        GridFieldText('item__source',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('source'))),
        GridFieldLastModified('item__lastmodified',
                              initially_hidden=True,
                              editable=False,
                              title=string_concat(_('item'), ' - ',
                                                  _('last modified'))),
        GridFieldText('location',
                      title=_('location'),
                      editable=False,
                      field_name='location__name',
                      formatter='detail',
                      extra='"role":"input/location"'),
        GridFieldText('location__description',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('location'), ' - ',
                                          _('description'))),
        GridFieldText('location__category',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('location'), ' - ',
                                          _('category'))),
        GridFieldText('location__subcategory',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('location'), ' - ',
                                          _('subcategory'))),
        GridFieldText('location__available',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('location'), ' - ',
                                          _('available')),
                      field_name='location__available__name',
                      formatter='detail',
                      extra='"role":"input/calendar"'),
        GridFieldLastModified('location__lastmodified',
                              initially_hidden=True,
                              editable=False,
                              title=string_concat(_('location'), ' - ',
                                                  _('last modified'))),
        GridFieldText('supplier',
                      title=_('supplier'),
                      editable=False,
                      field_name='supplier__name',
                      formatter='detail',
                      extra='"role":"input/supplier"'),
        GridFieldText('supplier__description',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('supplier'), ' - ',
                                          _('description'))),
        GridFieldText('supplier__category',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('supplier'), ' - ',
                                          _('category'))),
        GridFieldText('supplier__subcategory',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('supplier'), ' - ',
                                          _('subcategory'))),
        GridFieldText('supplier__owner',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('supplier'), ' - ', _('owner')),
                      field_name='supplier__owner__name'),
        GridFieldText('supplier__source',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('supplier'), ' - ', _('source'))),
        GridFieldLastModified('supplier__lastmodified',
                              initially_hidden=True,
                              editable=False,
                              title=string_concat(_('supplier'), ' - ',
                                                  _('last modified'))),
    )

    crosses = (
        ('proposed_start', {
            'title': _('proposed ordering')
        }),
        ('total_start', {
            'title': _('total ordering')
        }),
        ('proposed_end', {
            'title': _('proposed receiving')
        }),
        ('total_end', {
            'title': _('total receiving')
        }),
        ('proposed_on_order', {
            'title': _('proposed on order')
        }),
        ('total_on_order', {
            'title': _('total on order')
        }),
    )

    @staticmethod
    def basequeryset(request, *args, **kwargs):
        current, start, end = getHorizon(request)
        return PurchaseOrder.objects.all() \
          .filter(startdate__lte=end, enddate__gte=start) \
          .annotate(key=RawSQL("coalesce(item_id,'') || coalesce(location_id,'') || coalesce(supplier_id,'')", ())) \
          .distinct('key') \
          .order_by()   # Ordering isn't compatible with the distinct

    @classmethod
    def _apply_sort(reportclass, request, query):
        '''
    Applies a sort to the query.
    '''
        sortname = None
        if request.GET.get('sidx', ''):
            # 1) Sorting order specified on the request
            sortname = "%s %s" % (request.GET['sidx'],
                                  request.GET.get('sord', 'asc'))
        elif request.prefs:
            # 2) Sorting order from the preferences
            sortname = "%s %s" % (request.prefs.get(
                'sidx', ''), request.GET.get('sord', 'asc'))
        if not sortname or sortname == " asc":
            # 3) Default sort order
            return query.order_by('key')
        else:
            # Validate the field does exist.
            # We only validate the first level field, and not the fields
            # on related models.
            sortargs = []
            for s in sortname.split(","):
                stripped = s.strip()
                if not stripped:
                    continue
                sortfield, direction = stripped.split(" ", 1)
                try:
                    query.order_by(sortfield).query.__str__()
                    if direction.strip() != "desc":
                        sortargs.append(sortfield)
                    else:
                        sortargs.append('-%s' % sortfield)
                except:
                    for r in reportclass.rows:
                        if r.name == sortfield:
                            try:
                                query.order_by(r.field_name).query.__str__()
                                if direction.strip() != "desc":
                                    sortargs.append(r.field_name)
                                else:
                                    sortargs.append('-%s' % r.field_name)
                            except:
                                # Can't sort on this field
                                pass
                            break
            if sortargs:
                return query.order_by(
                    'key', *sortargs
                )  # The extra ordering by the 'key' is only change with the default method
            else:
                return query.order_by(
                    'key'
                )  # The extra ordering by the 'key' is only change with the default method

    @staticmethod
    def query(request, basequery, sortsql='1 asc'):
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)
        # Build the query
        query = '''
      with combinations as (%s)
      select row_to_json(data)
      from (
      select
        -- Key field
        combinations.key as key,
        -- Attribute fields of item, location and supplier
        combinations.item_id as item,
        item.description as item__description,
        item.category as item__category,
        item.subcategory as item__subcategory,
        item.cost as item__cost,
        item.owner_id as item__owner,
        item.source as item__source,
        item.lastmodified as item__lastmodified,
        combinations.location_id as location,
        location.description as location__description,
        location.category as location__category,
        location.subcategory as location__subcategory,
        location.available_id as location__available,
        location.lastmodified as location__lastmodified,
        combinations.supplier_id as supplier,
        supplier.description as supplier__description,
        supplier.category as supplier__category,
        supplier.subcategory as supplier_subcategory,
        supplier.owner_id as supplier__owner,
        supplier.source as supplier__source,
        supplier.lastmodified as supplier_lastmodified,
        -- Buckets
        res.bucket as bucket,
        to_char(res.startdate, 'YYYY-MM-DD') as startdate,
        to_char(res.enddate, 'YYYY-MM-DD') as enddate,
        -- Values
        res.proposed_start as proposed_start,
        res.total_start as total_start,
        res.proposed_end as proposed_end,
        res.total_end as total_end,
        res.proposed_on_order as proposed_on_order,
        res.total_on_order as total_on_order
      from combinations
      inner join item on combinations.item_id = item.name
      left outer join location on combinations.location_id = location.name
      left outer join supplier on combinations.supplier_id = supplier.name
      inner join (
        select
          operationplan.item_id, operationplan.location_id, operationplan.supplier_id,
          d.bucket, d.startdate, d.enddate,
          coalesce(sum(
            case when operationplan.status = 'proposed'
              and d.startdate <= operationplan.startdate and d.enddate > operationplan.startdate
            then operationplan.quantity
            else 0 end
            ), 0) proposed_start,
          coalesce(sum(
            case when d.startdate <= operationplan.startdate and d.enddate > operationplan.startdate
            then operationplan.quantity else 0 end
            ), 0) total_start,
          coalesce(sum(
            case when operationplan.status = 'proposed'
              and d.startdate <= operationplan.enddate and d.enddate > operationplan.enddate
             then operationplan.quantity else 0 end
            ), 0) proposed_end,
          coalesce(sum(
            case when d.startdate <= operationplan.enddate and d.enddate > operationplan.enddate
            then operationplan.quantity else 0 end
            ), 0) total_end,
          coalesce(sum(
            case when operationplan.status = 'proposed'
              and d.enddate > operationplan.startdate and d.enddate <= operationplan.enddate
             then operationplan.quantity else 0 end
            ), 0) proposed_on_order,
          coalesce(sum(
            case when d.enddate > operationplan.startdate and d.enddate <= operationplan.enddate
            then operationplan.quantity else 0 end
            ), 0) total_on_order
        from operationplan
        inner join  combinations
        on operationplan.item_id = combinations.item_id
          and operationplan.location_id = combinations.location_id
          and operationplan.supplier_id = combinations.supplier_id
        cross join (
          select name as bucket, startdate, enddate
          from common_bucketdetail
          where bucket_id = '%s' and enddate > '%s' and startdate < '%s'
          ) d
        where operationplan.type = 'PO'
        group by operationplan.item_id, operationplan.location_id, operationplan.supplier_id,
          d.bucket, d.startdate, d.enddate
        ) res
      on res.item_id = combinations.item_id
        and res.location_id = combinations.location_id
        and res.supplier_id = combinations.supplier_id
      order by %s, res.startdate
      ) data
      ''' % (basesql, request.report_bucket, request.report_startdate,
             request.report_enddate, sortsql)

        # Convert the SQL results to Python
        with connections[request.database].chunked_cursor() as cursor_chunked:
            cursor_chunked.execute(query, baseparams)
            for row in cursor_chunked:
                yield row[0]
コード例 #16
0
class PurchaseOrderList(OperationPlanMixin, GridReport):
    template = "input/operationplanreport.html"
    title = _("purchase orders")
    model = PurchaseOrder
    default_sort = (1, "desc")
    frozenColumns = 1
    multiselect = True
    editable = True
    height = 250
    help_url = "modeling-wizard/purchasing/purchase-orders.html"
    message_when_empty = Template(
        """
        <h3>Define purchase orders</h3>
        <br>
        This table defines ongoing and proposed purchase orders.<br><br>
        Use this table to load ongoing purchase orders in the status "confirmed".<br><br>
        The planning algorithm will further populate this table with additional "proposed" purchase orders for the future.<br>
        <br><br>
        <div role="group" class="btn-group.btn-group-justified">
        <a href="{{request.prefix}}/data/input/purchaseorder/add/" onclick="window.location = $(event.target).attr('href')" class="btn btn-primary">Create a single purchase order<br>in a form</a>
        <a href="{{request.prefix}}/wizard/load/production/?currentstep=7" onclick="window.location = $(event.target).attr('href')" class="btn btn-primary">Wizard to upload purchase orders<br>from a spreadsheet</a>
        </div>
        <br>
        """
    )
    calendarmode = "start_end"

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session["lasttab"] = "purchaseorders"
            paths = request.path.split("/")
            path = paths[4]
            if path == "supplier" or request.path.startswith("/detail/input/supplier/"):
                return {
                    "default_operationplan_type": "PO",
                    "groupBy": "status",
                    "active_tab": "purchaseorders",
                    "model": Supplier,
                    "title": force_text(Supplier._meta.verbose_name) + " " + args[0],
                    "post_title": _("purchase orders"),
                }
            elif path == "location" or request.path.startswith(
                "/detail/input/location/"
            ):
                return {
                    "default_operationplan_type": "PO",
                    "groupBy": "status",
                    "active_tab": "purchaseorders",
                    "model": Location,
                    "title": force_text(Location._meta.verbose_name) + " " + args[0],
                    "post_title": _("purchase orders"),
                }
            elif path == "item" or request.path.startswith("/detail/input/item/"):
                return {
                    "default_operationplan_type": "PO",
                    "groupBy": "status",
                    "active_tab": "purchaseorders",
                    "model": Item,
                    "title": force_text(Item._meta.verbose_name) + " " + args[0],
                    "post_title": _("purchase orders"),
                }
            elif path == "operationplanmaterial":
                return {
                    "default_operationplan_type": "PO",
                    "groupBy": "status",
                    "active_tab": "purchaseorders",
                    "model": Item,
                    "title": force_text(Item._meta.verbose_name) + " " + args[0],
                    "post_title": force_text(
                        _("on order in %(loc)s at %(date)s")
                        % {"loc": args[1], "date": args[2]}
                    ),
                }
            elif path == "produced":
                return {
                    "default_operationplan_type": "PO",
                    "groupBy": "status",
                    "active_tab": "purchaseorders",
                    "model": Item,
                    "title": force_text(Item._meta.verbose_name) + " " + args[0],
                    "post_title": force_text(
                        _("on order in %(loc)s between %(date1)s and %(date2)s")
                        % {"loc": args[1], "date1": args[2], "date2": args[3]}
                    ),
                }
            else:
                return {
                    "default_operationplan_type": "PO",
                    "groupBy": "status",
                    "active_tab": "edit",
                    "model": Item,
                }
        elif "parentreference" in request.GET:
            return {
                "default_operationplan_type": "PO",
                "groupBy": "status",
                "active_tab": "edit",
                "title": force_text(PurchaseOrder._meta.verbose_name)
                + " "
                + request.GET["parentreference"],
            }
        else:
            return {
                "default_operationplan_type": "PO",
                "groupBy": "status",
                "active_tab": "purchaseorders",
            }

    @classmethod
    def basequeryset(reportclass, request, *args, **kwargs):
        q = PurchaseOrder.objects.all()
        if "calendarstart" in request.GET:
            q = q.filter(
                Q(enddate__gte=request.GET["calendarstart"])
                | (
                    Q(enddate__isnull=True)
                    & Q(startdate__gte=request.GET["calendarstart"])
                )
            )
        if "calendarend" in request.GET:
            q = q.filter(
                Q(startdate__lte=request.GET["calendarend"])
                | (
                    Q(startdate__isnull=True)
                    & Q(enddate__lte=request.GET["calendarend"])
                )
            )
        if args and args[0]:
            paths = request.path.split("/")
            path = paths[4]
            if paths[4] == "operationplanmaterial":
                q = q.filter(
                    location__name=args[1],
                    item__name=args[0],
                    startdate__lt=args[2],
                    enddate__gte=args[2],
                )
            elif path == "produced":
                q = q.filter(
                    location__name=args[1],
                    item__name=args[0],
                    enddate__gte=args[2],
                    enddate__lt=args[3],
                )
            elif path == "supplier" or request.path.startswith(
                "/detail/input/supplier/"
            ):
                try:
                    Supplier.rebuildHierarchy(database=request.database)
                    sup = (
                        Supplier.objects.all().using(request.database).get(name=args[0])
                    )
                    lft = sup.lft
                    rght = sup.rght
                except Supplier.DoesNotExist:
                    lft = 1
                    rght = 1
                q = q.filter(supplier__lft__gte=lft, supplier__rght__lte=rght)
            elif path == "location" or request.path.startswith(
                "/detail/input/location/"
            ):
                try:
                    Location.rebuildHierarchy(database=request.database)
                    loc = (
                        Location.objects.all().using(request.database).get(name=args[0])
                    )
                    lft = loc.lft
                    rght = loc.rght
                except Location.DoesNotExist:
                    lft = 1
                    rght = 1
                q = q.filter(location__lft__gte=lft, location__rght__lte=rght)
            elif path == "item" or request.path.startswith("/detail/input/item/"):
                try:
                    Item.rebuildHierarchy(database=request.database)
                    itm = Item.objects.all().using(request.database).get(name=args[0])
                    lft = itm.lft
                    rght = itm.rght
                except Item.DoesNotExist:
                    lft = 1
                    rght = 1
                q = q.filter(item__lft__gte=lft, item__rght__lte=rght)

        q = reportclass.operationplanExtraBasequery(q.select_related("item"), request)
        return q.annotate(
            unit_cost=Cast(
                RawSQL(
                    """
                    coalesce((
                      select cost
                      from itemsupplier
                      where itemsupplier.item_id = operationplan.item_id
                        and (itemsupplier.location_id is null or itemsupplier.location_id = operationplan.location_id)
                        and itemsupplier.supplier_id = operationplan.supplier_id
                      order by operationplan.enddate < itemsupplier.effective_end desc nulls first,
                         operationplan.enddate >= itemsupplier.effective_start desc nulls first,
                         priority <> 0,
                         priority
                      limit 1),
                     (select cost from item where item.name = operationplan.item_id), 0)
                    """,
                    [],
                ),
                output_field=FloatField(),
            ),
            total_cost=Cast(F("unit_cost") * F("quantity"), output_field=FloatField()),
            total_volume=Cast(
                F("item__volume") * F("quantity"), output_field=FloatField()
            ),
            total_weight=Cast(
                F("item__weight") * F("quantity"), output_field=FloatField()
            ),
            feasible=RawSQL(
                "coalesce((operationplan.plan->>'feasible')::boolean, true)", []
            ),
            computed_color=RawSQL(
                """
                case when operationplan.color >= 999999 and operationplan.plan ? 'item' then
                999999
                - extract(epoch from operationplan.delay)/86400.0
                + 1000000
                when operationplan.color >= 999999 and not(operationplan.plan ? 'item') then
                999999
                - extract(epoch from operationplan.delay)/86400.0
                else operationplan.color
                end
                """,
                [],
            ),
            itemsupplier_sizeminimum=Cast(
                RawSQL(
                    """
                    select sizeminimum
                    from itemsupplier
                    where itemsupplier.item_id = operationplan.item_id
                      and (itemsupplier.location_id is null or itemsupplier.location_id = operationplan.location_id)
                      and itemsupplier.supplier_id = operationplan.supplier_id
                    order by operationplan.enddate < itemsupplier.effective_end desc nulls first,
                       operationplan.enddate >= itemsupplier.effective_start desc nulls first,
                       priority <> 0,
                       priority
                    limit 1
                    """,
                    [],
                ),
                output_field=FloatField(),
            ),
            itemsupplier_sizemultiple=Cast(
                RawSQL(
                    """
                    select sizemultiple
                    from itemsupplier
                    where itemsupplier.item_id = operationplan.item_id
                      and (itemsupplier.location_id is null or itemsupplier.location_id = operationplan.location_id)
                      and itemsupplier.supplier_id = operationplan.supplier_id
                    order by operationplan.enddate < itemsupplier.effective_end desc nulls first,
                       operationplan.enddate >= itemsupplier.effective_start desc nulls first,
                       priority <> 0,
                       priority
                    limit 1
                    """,
                    [],
                ),
                output_field=FloatField(),
            ),
            itemsupplier_sizemaximum=Cast(
                RawSQL(
                    """
                    select sizemaximum
                    from itemsupplier
                    where itemsupplier.item_id = operationplan.item_id
                      and (itemsupplier.location_id is null or itemsupplier.location_id = operationplan.location_id)
                      and itemsupplier.supplier_id = operationplan.supplier_id
                    order by operationplan.enddate < itemsupplier.effective_end desc nulls first,
                       operationplan.enddate >= itemsupplier.effective_start desc nulls first,
                       priority <> 0,
                       priority
                    limit 1
                    """,
                    [],
                ),
                output_field=FloatField(),
            ),
            itemsupplier_priority=Cast(
                RawSQL(
                    """
                    select priority
                    from itemsupplier
                    where itemsupplier.item_id = operationplan.item_id
                      and (itemsupplier.location_id is null or itemsupplier.location_id = operationplan.location_id)
                      and itemsupplier.supplier_id = operationplan.supplier_id
                    order by operationplan.enddate < itemsupplier.effective_end desc nulls first,
                       operationplan.enddate >= itemsupplier.effective_start desc nulls first,
                       priority <> 0,
                       priority
                    limit 1
                    """,
                    [],
                ),
                output_field=FloatField(),
            ),
            itemsupplier_effective_start=Cast(
                RawSQL(
                    """
                    select effective_start
                    from itemsupplier
                    where itemsupplier.item_id = operationplan.item_id
                      and (itemsupplier.location_id is null or itemsupplier.location_id = operationplan.location_id)
                      and itemsupplier.supplier_id = operationplan.supplier_id
                    order by operationplan.enddate < itemsupplier.effective_end desc nulls first,
                       operationplan.enddate >= itemsupplier.effective_start desc nulls first,
                       priority <> 0,
                       priority
                    limit 1
                    """,
                    [],
                ),
                output_field=DateTimeField(),
            ),
            itemsupplier_effective_end=Cast(
                RawSQL(
                    """
                    select effective_end
                    from itemsupplier
                    where itemsupplier.item_id = operationplan.item_id
                      and (itemsupplier.location_id is null or itemsupplier.location_id = operationplan.location_id)
                      and itemsupplier.supplier_id = operationplan.supplier_id
                    order by operationplan.enddate < itemsupplier.effective_end desc nulls first,
                       operationplan.enddate >= itemsupplier.effective_start desc nulls first,
                       priority <> 0,
                       priority
                    limit 1
                    """,
                    [],
                ),
                output_field=DateTimeField(),
            ),
        )

    rows = (
        GridFieldText(
            "reference",
            title=_("reference"),
            key=True,
            formatter="detail",
            extra='role:"input/purchaseorder"',
            editable=not settings.ERP_CONNECTOR,
        ),
        GridFieldNumber(
            "computed_color",
            title=_("inventory status"),
            formatter="color",
            width="125",
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"',
        ),
        GridFieldNumber("color", hidden=True),
        GridFieldHierarchicalText(
            "item",
            title=_("item"),
            field_name="item__name",
            formatter="detail",
            extra='"role":"input/item"',
            model=Item,
        ),
        GridFieldHierarchicalText(
            "location",
            title=_("location"),
            field_name="location__name",
            formatter="detail",
            extra='"role":"input/location"',
            model=Location,
        ),
        GridFieldHierarchicalText(
            "supplier",
            title=_("supplier"),
            field_name="supplier__name",
            formatter="detail",
            extra='"role":"input/supplier"',
            model=Supplier,
        ),
        GridFieldDateTime(
            "startdate",
            title=_("ordering date"),
            extra='"formatoptions":{"srcformat":"Y-m-d H:i:s","newformat":"Y-m-d H:i:s", "defaultValue":""}, "summaryType":"min"',
        ),
        GridFieldDateTime(
            "enddate",
            title=_("receipt date"),
            extra='"formatoptions":{"srcformat":"Y-m-d H:i:s","newformat":"Y-m-d H:i:s", "defaultValue":""}, "summaryType":"max"',
        ),
        GridFieldNumber(
            "quantity",
            title=_("quantity"),
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"sum"',
        ),
        GridFieldChoice(
            "status",
            title=_("status"),
            choices=PurchaseOrder.orderstatus,
            editable=not settings.ERP_CONNECTOR,
        ),
        GridFieldCurrency(
            "unit_cost",
            title=format_lazy("{} - {}", _("item"), _("cost")),
            editable=False,
            search=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"max"',
        ),
        GridFieldCurrency(
            "total_cost",
            title=_("total cost"),
            editable=False,
            search=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"sum"',
        ),
        GridFieldNumber(
            "total_volume",
            title=_("total volume"),
            editable=False,
            search=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"sum"',
        ),
        GridFieldNumber(
            "total_weight",
            title=_("total weight"),
            editable=False,
            search=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"sum"',
        ),
        GridFieldText(
            "batch", title=_("batch"), editable="true", initially_hidden=True
        ),
        GridFieldNumber(
            "criticality",
            title=_("criticality"),
            editable=False,
            initially_hidden=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"',
        ),
        GridFieldDuration(
            "delay",
            title=_("delay"),
            editable=False,
            initially_hidden=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"max"',
        ),
        GridFieldJSON(
            "demands",
            title=_("demands"),
            editable=False,
            search=True,
            sortable=False,
            formatter="demanddetail",
            extra='"role":"input/demand"',
        ),
        GridFieldText("source", title=_("source"), initially_hidden=True),
        GridFieldBool(
            "feasible",
            title=_("feasible"),
            editable=False,
            initially_hidden=True,
            search=True,
        ),
        GridFieldLastModified("lastmodified"),
        # Annoted fields referencing the itemsupplier
        GridFieldNumber(
            "itemsupplier_sizeminimum",
            title=format_lazy("{} - {}", _("item supplier"), _("size minimum")),
            editable=False,
            initially_hidden=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"',
        ),
        GridFieldNumber(
            "itemsupplier_sizemultiple",
            title=format_lazy("{} - {}", _("item supplier"), _("size multiple")),
            editable=False,
            initially_hidden=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"',
        ),
        GridFieldNumber(
            "itemsupplier_sizemaximum",
            title=format_lazy("{} - {}", _("item supplier"), _("size maximum")),
            editable=False,
            initially_hidden=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"',
        ),
        GridFieldDateTime(
            "itemsupplier_effective_end",
            title=format_lazy("{} - {}", _("item supplier"), _("effective end")),
            editable=False,
            initially_hidden=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"',
        ),
        GridFieldDateTime(
            "itemsupplier_effective_start",
            title=format_lazy("{} - {}", _("item supplier"), _("effective start")),
            editable=False,
            initially_hidden=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"',
        ),
        GridFieldNumber(
            "itemsupplier_priority",
            title=format_lazy("{} - {}", _("item supplier"), _("priority")),
            editable=False,
            initially_hidden=True,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"',
        ),
        # Optional fields referencing the item
        GridFieldText(
            "item__type",
            title=format_lazy("{} - {}", _("item"), _("type")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "item__description",
            title=format_lazy("{} - {}", _("item"), _("description")),
            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__volume",
            title=format_lazy("{} - {}", _("item"), _("volume")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldNumber(
            "item__weight",
            title=format_lazy("{} - {}", _("item"), _("weight")),
            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="location__available__name",
            formatter="detail",
            extra='"role":"input/calendar"',
            editable=False,
        ),
        GridFieldText(
            "location__owner",
            title=format_lazy("{} - {}", _("location"), _("owner")),
            initially_hidden=True,
            field_name="location__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,
        ),
        # Optional fields referencing the supplier
        GridFieldText(
            "supplier__description",
            title=format_lazy("{} - {}", _("supplier"), _("description")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "supplier__category",
            title=format_lazy("{} - {}", _("supplier"), _("category")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "supplier__subcategory",
            title=format_lazy("{} - {}", _("supplier"), _("subcategory")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "supplier__owner",
            title=format_lazy("{} - {}", _("supplier"), _("owner")),
            initially_hidden=True,
            field_name="supplier__owner__name",
            formatter="detail",
            extra='"role":"input/supplier"',
            editable=False,
        ),
        GridFieldText(
            "supplier__source",
            title=format_lazy("{} - {}", _("supplier"), _("source")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldLastModified(
            "supplier__lastmodified",
            title=format_lazy("{} - {}", _("supplier"), _("last modified")),
            initially_hidden=True,
            editable=False,
        ),
        GridFieldText(
            "end_items",
            title=_("end items"),
            editable=False,
            search=False,
            sortable=False,
            initially_hidden=True,
            formatter="listdetail",
            extra='"role":"input/item"',
        ),
    )

    if settings.ERP_CONNECTOR:
        actions = [
            {
                "name": "erp_incr_export",
                "label": format_lazy("export to {erp}", erp=settings.ERP_CONNECTOR),
                "function": "ERPconnection.IncrementalExport(jQuery('#grid'),'PO')",
            }
        ]
    else:
        actions = [
            {
                "name": "proposed",
                "label": format_lazy(
                    _("change status to {status}"), status=_("proposed")
                ),
                "function": "grid.setStatus('proposed')",
            },
            {
                "name": "approved",
                "label": format_lazy(
                    _("change status to {status}"), status=_("approved")
                ),
                "function": "grid.setStatus('approved')",
            },
            {
                "name": "confirmed",
                "label": format_lazy(
                    _("change status to {status}"), status=_("confirmed")
                ),
                "function": "grid.setStatus('confirmed')",
            },
            {
                "name": "completed",
                "label": format_lazy(
                    _("change status to {status}"), status=_("completed")
                ),
                "function": "grid.setStatus('completed')",
            },
            {
                "name": "closed",
                "label": format_lazy(
                    _("change status to {status}"), status=_("closed")
                ),
                "function": "grid.setStatus('closed')",
            },
        ]

    @classmethod
    def initialize(reportclass, request):
        if reportclass._attributes_added != 2:
            reportclass._attributes_added = 2
            for f in getAttributeFields(PurchaseOrder):
                reportclass.rows += (f,)
            for f in getAttributeFields(Item, related_name_prefix="item"):
                f.editable = False
                reportclass.rows += (f,)
            for f in getAttributeFields(Location, related_name_prefix="location"):
                f.editable = False
                reportclass.rows += (f,)
            for f in getAttributeFields(Supplier, related_name_prefix="supplier"):
                f.editable = False
                reportclass.rows += (f,)
コード例 #17
0
ファイル: buffer.py プロジェクト: westlyou/frepple
class OverviewReport(GridPivot):
    '''
  A report showing the inventory profile of buffers.
  '''
    template = 'output/buffer.html'
    title = _('Inventory report')

    @classmethod
    def basequeryset(reportclass, request, args, kwargs):
        if len(args) and args[0]:
            return Buffer.objects.all()
        else:
            return OperationPlanMaterial.objects.all() \
              .order_by('item_id', 'location_id') \
              .distinct('item_id', 'location_id') \
              .annotate(buffer=Concat('item', Value(' @ '), 'location'))

    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=string_concat(_('item'), ' - ', _('description')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('item__category',
                      title=string_concat(_('item'), ' - ', _('category')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('item__subcategory',
                      title=string_concat(_('item'), ' - ', _('subcategory')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('item__owner',
                      title=string_concat(_('item'), ' - ', _('owner')),
                      field_name='item__owner__name',
                      initially_hidden=True,
                      editable=False),
        GridFieldText('item__source',
                      title=string_concat(_('item'), ' - ', _('source')),
                      initially_hidden=True,
                      editable=False),
        GridFieldLastModified('item__lastmodified',
                              title=string_concat(_('item'), ' - ',
                                                  _('last modified')),
                              initially_hidden=True,
                              editable=False),
        # Optional fields referencing the location
        GridFieldText('location__description',
                      title=string_concat(_('location'), ' - ',
                                          _('description')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('location__category',
                      title=string_concat(_('location'), ' - ', _('category')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('location__subcategory',
                      title=string_concat(_('location'), ' - ',
                                          _('subcategory')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('location__available',
                      title=string_concat(_('location'), ' - ',
                                          _('available')),
                      initially_hidden=True,
                      field_name='origin__available__name',
                      formatter='detail',
                      extra='"role":"input/calendar"',
                      editable=False),
        GridFieldText('location__owner',
                      title=string_concat(_('location'), ' - ', _('owner')),
                      initially_hidden=True,
                      field_name='origin__owner__name',
                      formatter='detail',
                      extra='"role":"input/location"',
                      editable=False),
        GridFieldText('location__source',
                      title=string_concat(_('location'), ' - ', _('source')),
                      initially_hidden=True,
                      editable=False),
        GridFieldLastModified('location__lastmodified',
                              title=string_concat(_('location'), ' - ',
                                                  _('last modified')),
                              initially_hidden=True,
                              editable=False),
    )

    crosses = (
        ('startoh', {
            'title': _('start inventory')
        }),
        ('produced', {
            'title': _('produced')
        }),
        ('consumed', {
            'title': _('consumed')
        }),
        ('endoh', {
            'title': _('end inventory')
        }),
    )

    @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, 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 args and args[0]:
            request.session['lasttab'] = 'plan'
            return {
                'title': force_text(Item._meta.verbose_name) + " " + args[0],
                'post_title': _('plan')
            }
        else:
            return {}

    @classmethod
    def query(reportclass, request, basequery, sortsql='1 asc'):
        cursor = connections[request.database].cursor()
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)

        # Execute a query  to get the onhand value at the start of our horizon
        startohdict = {}
        query = '''
      select opplanmat.item_id, opplanmat.location_id, sum(oh.onhand)
      from (%s) opplanmat
      inner join (
        select operationplanmaterial.item_id,
          operationplanmaterial.location_id,
          operationplanmaterial.onhand as onhand
        from operationplanmaterial,
          (select item_id, location_id, max(id) as id
           from operationplanmaterial
           where flowdate < '%s'
           group by item_id, location_id
          ) maxid
        where maxid.item_id = operationplanmaterial.item_id
          and maxid.location_id = operationplanmaterial.location_id
        and maxid.id = operationplanmaterial.id
      ) oh
      on oh.item_id = opplanmat.item_id
      and oh.location_id = opplanmat.location_id
      group by opplanmat.item_id, opplanmat.location_id
      ''' % (basesql, request.report_startdate)
        cursor.execute(query, baseparams)
        for row in cursor.fetchall():
            startohdict["%s @ %s" % (row[0], row[1])] = float(row[2])

        # Execute the actual query
        query = '''
      select
        invplan.item_id || ' @ ' || invplan.location_id,
        invplan.item_id, invplan.location_id, 
        item.description, item.category, item.subcategory, item.owner_id,
        item.source, item.lastmodified, location.description, location.category,
        location.subcategory, location.available_id, location.owner_id, 
        location.source, location.lastmodified, %s
        invplan.bucket, invplan.startdate, invplan.enddate,
        invplan.consumed, invplan.produced
      from (
        select
          opplanmat.item_id, opplanmat.location_id,
          d.bucket as bucket, d.startdate as startdate, d.enddate as enddate,
          coalesce(sum(greatest(operationplanmaterial.quantity, 0)),0) as consumed,
          coalesce(-sum(least(operationplanmaterial.quantity, 0)),0) as produced
        from (%s) opplanmat
        -- 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
        -- Consumed and produced quantities
        left join operationplanmaterial
        on opplanmat.item_id = operationplanmaterial.item_id
        and opplanmat.location_id = operationplanmaterial.location_id
        and d.startdate <= operationplanmaterial.flowdate
        and d.enddate > operationplanmaterial.flowdate
        and operationplanmaterial.flowdate >= %%s
        and operationplanmaterial.flowdate < %%s
        -- Grouping and sorting
        group by opplanmat.item_id, opplanmat.location_id, d.bucket, d.startdate, d.enddate
        ) invplan
      left outer join item on
        invplan.item_id = item.name
      left outer join location on
        invplan.location_id = location.name
      order by %s, invplan.startdate
      ''' % (reportclass.attr_sql, basesql, sortsql)
        cursor.execute(
            query,
            baseparams + (request.report_bucket, request.report_startdate,
                          request.report_enddate, request.report_startdate,
                          request.report_enddate))

        # Build the python result
        prevbuf = None
        for row in cursor.fetchall():
            numfields = len(row)
            if row[0] != prevbuf:
                prevbuf = row[0]
                startoh = startohdict.get(prevbuf, 0)
                endoh = startoh + float(row[numfields - 2] -
                                        row[numfields - 1])
            else:
                startoh = endoh
                endoh += float(row[numfields - 2] - row[numfields - 1])
            res = {
                'buffer': row[0],
                'item': row[1],
                'location': row[2],
                'item__description': row[3],
                'item__category': row[4],
                'item__subcategory': row[5],
                'item__owner': row[6],
                'item__source': row[7],
                'item__lastmodified': row[8],
                'location__description': row[9],
                'location__category': row[10],
                'location__subcategory': row[11],
                'location__available_id': row[12],
                'location__owner_id': row[13],
                'location__source': row[14],
                'location__lastmodified': row[15],
                'bucket': row[numfields - 5],
                'startdate': row[numfields - 4].date(),
                'enddate': row[numfields - 3].date(),
                'startoh': round(startoh, 1),
                'produced': round(row[numfields - 2], 1),
                'consumed': round(row[numfields - 1], 1),
                'endoh': round(endoh, 1),
            }
            # Add attribute fields
            idx = 16
            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
コード例 #18
0
class Report(GridReport):
    title = _("Performance Indicators")
    frozenColumns = 0
    basequeryset = Parameter.objects.all()
    permissions = (("view_kpi_report", "Can view kpi report"), )
    rows = (
        GridFieldText('category',
                      title=_('category'),
                      sortable=False,
                      editable=False,
                      align='center'),
        #. Translators: Translation included with Django
        GridFieldText('name',
                      title=_('name'),
                      sortable=False,
                      editable=False,
                      align='center'),
        GridFieldInteger('value',
                         title=_('value'),
                         sortable=False,
                         editable=False,
                         align='center'),
    )
    default_sort = (1, 'asc')
    filterable = False
    multiselect = False
    help_url = 'user-guide/user-interface/plan-analysis/performance-indicator-report.html'

    @staticmethod
    def query(request, basequery):
        # Execute the query
        cursor = connections[request.database].cursor()
        cursor.execute('''
      select 101 as id, 'Problem count' as category, name as name, count(*) as value
      from out_problem
      group by name
      union all
      select 102, 'Problem weight', name, round(sum(weight))
      from out_problem
      group by name
      union all
      select 201, 'Demand', 'Requested', coalesce(round(sum(quantity)),0)
      from demand
      where status in ('open', 'quote')
      union all
      select 202, 'Demand', 'Planned', coalesce(round(sum(quantity)),0)
      from operationplan
      where demand_id is not null and owner_id is null
      union all
      select 203, 'Demand', 'Planned late', coalesce(round(sum(quantity)),0)
      from operationplan
      where enddate > due and demand_id is not null and owner_id is null
      union all
      select 204, 'Demand', 'Planned on time', coalesce(round(sum(quantity)),0)
      from operationplan
      where enddate <= due and demand_id is not null and owner_id is null
      union all
      select 205, 'Demand', 'Unplanned', coalesce(round(sum(weight)),0)
      from out_problem
      where name = 'unplanned'
      union all
      select 206, 'Demand', 'Total lateness', coalesce(round(sum(quantity * extract(epoch from enddate - due)) / 86400),0)
      from operationplan
      where enddate > due and demand_id is not null and owner_id is null
      union all
      select 301, 'Operation', 'Count', count(*)
      from operationplan
      union all
      select 301, 'Operation', 'Quantity', coalesce(round(sum(quantity)),0)
      from operationplan
      union all
      select 302, 'Resource', 'Usage', coalesce(round(sum(quantity * extract(epoch from enddate - startdate)) / 86400),0)
      from operationplanresource
      union all
      select 401, 'Material', 'Produced', coalesce(round(sum(quantity)),0)
      from operationplanmaterial
      where quantity>0
      union all
      select 402, 'Material', 'Consumed', coalesce(round(sum(-quantity)),0)
      from operationplanmaterial
      where quantity<0
      order by 1
      ''')

        # Build the python result
        for row in cursor.fetchall():
            yield {
                'category': row[1],
                'name': row[2],
                'value': row[3],
            }
コード例 #19
0
ファイル: constraint.py プロジェクト: zodioo-team/frepple
class BaseReport(GridReport):
    """
  A list report to show constraints.
  """

    template = "output/constraint.html"
    title = _("Constraint report")
    basequeryset = Constraint.objects.all()
    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,
                "model":
                reportclass.detailmodel,
            }
        else:
            return {"active_tab": "constraint"}
コード例 #20
0
ファイル: views.py プロジェクト: xfyecn/frepple
class TaskReport(GridReport):
    """
    A list report to review the history of actions.
    """

    template = "execute/execute.html"
    title = _("Task status")
    basequeryset = (Task.objects.all().extra(
        select={
            "duration":
            "case when status in ('Done', '100%%') then finished::timestamp(0) - started::timestamp(0) end"
        }).select_related("user"))
    model = Task
    frozenColumns = 0
    multiselect = False
    editable = False
    height = 150
    default_sort = (0, "desc")
    help_url = "user-interface/execute.html"

    rows = (
        GridFieldInteger("id", title=_("identifier"), key=True),
        GridFieldText("name", title=_("name"), editable=False, align="center"),
        GridFieldLocalDateTime("submitted",
                               title=_("submitted"),
                               editable=False,
                               align="center"),
        GridFieldLocalDateTime("started",
                               title=_("started"),
                               editable=False,
                               align="center"),
        GridFieldLocalDateTime("finished",
                               title=_("finished"),
                               editable=False,
                               align="center"),
        GridFieldText(
            "status",
            title=_("status"),
            editable=False,
            align="center",
            extra="formatter:status",
        ),
        GridFieldText(
            "logfile",
            title=_("log file"),
            width=80,
            editable=False,
            align="center",
            extra="formatter:logbutton",
        ),
        GridFieldText(
            "message",
            title=_("message"),
            editable=False,
            width=500,
            formatter="longstring",
        ),
        GridFieldText("arguments",
                      title=_("arguments"),
                      formatter="longstring",
                      editable=False),
        GridFieldText(
            "user",
            title=_("user"),
            field_name="user__username",
            editable=False,
            align="center",
        ),
        GridFieldDuration(
            "duration",
            title=_("duration"),
            search=False,
            editable=False,
            align="center",
        ),
        GridFieldBool("cancelable", title="cancelable", hidden=True),
    )

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        # Loop over all accordion of all apps and directories
        accordions = set()
        accord = ""
        for commandname, appname in get_commands().items():
            try:
                accord = getattr(
                    import_module("%s.management.commands.%s" %
                                  (appname, commandname)),
                    "Command",
                )
                if getattr(accord, "index", -1) >= 0 and getattr(
                        accord, "getHTML", None):
                    accordions.add(accord)
            except Exception as e:
                logger.warn(
                    "Couldn't import getHTML method from %s.management.commands.%s: %s"
                    % (appname, commandname, e))

        accordions = sorted(accordions, key=operator.attrgetter("index"))

        # Send to template
        return {"commandlist": accordions}

    @classmethod
    def query(reportclass, request, basequery, sortsql="1 asc"):
        logfileslist = set([
            x for x in os.listdir(settings.FREPPLE_LOGDIR)
            if x.endswith(".log")
        ])
        for rec in basequery:
            yield {
                "id": rec.id,
                "name": rec.name,
                "submitted": rec.submitted,
                "started": rec.started,
                "finished": rec.finished,
                "status": rec.status,
                "logfile":
                rec.logfile if rec.logfile in logfileslist else None,
                "message": rec.message,
                "arguments": rec.arguments,
                "user__username": rec.user.username if rec.user else None,
                "duration": rec.duration,
                "cancelable": rec.processid is not None
                or rec.status == "Waiting",
            }

    @classmethod
    def extraJSON(reportclass, request):
        try:
            lastCompletedTask = (Task.objects.all().using(
                request.database).filter(
                    status="Done").order_by("-id").only("id")[0])
            return '"lastcompleted":%d,\n' % lastCompletedTask.id
        except Exception:
            return '"lastcompleted":0,\n'
コード例 #21
0
class DistributionReport(GridPivot):
    """
  A report summarizing all distribution orders.
  """

    template = "output/distribution_order_summary.html"
    title = _("Distribution order summary")
    model = DistributionOrder
    permissions = (("view_distributionorder", "Can view distribution order"), )
    help_url = "user-guide/user-interface/plan-analysis/distribution-order-summary.html"

    rows = (
        GridFieldText(
            "key",
            key=True,
            search=False,
            initially_hidden=True,
            hidden=True,
            field_name="item__name",
            editable=False,
        ),
        GridFieldText(
            "item",
            title=_("item"),
            editable=False,
            field_name="item__name",
            formatter="detail",
            extra='"role":"input/item"',
        ),
        GridFieldText(
            "item__description",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("description")),
        ),
        GridFieldText(
            "item__category",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("category")),
        ),
        GridFieldText(
            "item__subcategory",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("subcategory")),
        ),
        GridFieldCurrency(
            "item__cost",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("cost")),
            field_name="item__cost",
        ),
        GridFieldText(
            "item__owner",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("owner")),
            field_name="item__owner__name",
        ),
        GridFieldText(
            "item__source",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("source")),
        ),
        GridFieldLastModified(
            "item__lastmodified",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("item"), _("last modified")),
        ),
        GridFieldText(
            "origin",
            title=_("origin"),
            editable=False,
            field_name="origin__name",
            formatter="detail",
            extra='"role":"input/location"',
        ),
        GridFieldText(
            "origin__description",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("origin"), _("description")),
        ),
        GridFieldText(
            "origin__category",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("origin"), _("category")),
        ),
        GridFieldText(
            "origin__subcategory",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("origin"), _("subcategory")),
        ),
        GridFieldText(
            "origin__available",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("origin"), _("available")),
            field_name="origin__available__name",
            formatter="detail",
            extra='"role":"input/calendar"',
        ),
        GridFieldLastModified(
            "origin__lastmodified",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("origin"), _("last modified")),
        ),
        GridFieldText(
            "destination",
            title=_("destination"),
            editable=False,
            field_name="destination__name",
            formatter="detail",
            extra='"role":"input/location"',
        ),
        GridFieldText(
            "destination__description",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("destination"), _("description")),
        ),
        GridFieldText(
            "destination__category",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("destination"), _("category")),
        ),
        GridFieldText(
            "destination__subcategory",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("destination"), _("subcategory")),
        ),
        GridFieldText(
            "destination__available",
            editable=False,
            initially_hidden=True,
            title=format_lazy("{} - {}", _("destination"), _("available")),
            field_name="destination__available__name",
            formatter="detail",
            extra='"role":"input/calendar"',
        ),
        GridFieldLastModified(
            "destination__lastmodified",
            initially_hidden=True,
            editable=False,
            title=format_lazy("{} - {}", _("destination"), _("last modified")),
        ),
    )

    crosses = (
        ("proposed_start", {
            "title": _("proposed shipping")
        }),
        ("total_start", {
            "title": _("total shipping")
        }),
        ("proposed_end", {
            "title": _("proposed receiving")
        }),
        ("total_end", {
            "title": _("total receiving")
        }),
        ("proposed_in_transit", {
            "title": _("proposed in transit")
        }),
        ("total_in_transit", {
            "title": _("total in transit")
        }),
    )

    @staticmethod
    def basequeryset(request, *args, **kwargs):
        current, start, end = getHorizon(request)
        return (DistributionOrder.objects.all(
        ).filter(startdate__lte=end, enddate__gte=start).annotate(key=RawSQL(
            "coalesce(item_id,'') || coalesce(origin_id,'') || coalesce(destination_id,'')",
            (),
        )).distinct("key").order_by()
                )  # Ordering isn't compatible with the distinct

    @classmethod
    def _apply_sort(reportclass, request, query):
        """
    Applies a sort to the query.
    """
        sortname = None
        if request.GET.get("sidx", ""):
            # 1) Sorting order specified on the request
            sortname = "%s %s" % (request.GET["sidx"],
                                  request.GET.get("sord", "asc"))
        elif request.prefs:
            # 2) Sorting order from the preferences
            sortname = "%s %s" % (
                request.prefs.get("sidx", ""),
                request.GET.get("sord", "asc"),
            )
        if not sortname or sortname == " asc":
            # 3) Default sort order
            return query.order_by("key")
        else:
            # Validate the field does exist.
            # We only validate the first level field, and not the fields
            # on related models.
            sortargs = []
            for s in sortname.split(","):
                stripped = s.strip()
                if not stripped:
                    continue
                sortfield, direction = stripped.split(" ", 1)
                try:
                    query.order_by(sortfield).query.__str__()
                    if direction.strip() != "desc":
                        sortargs.append(sortfield)
                    else:
                        sortargs.append("-%s" % sortfield)
                except Exception:
                    for r in reportclass.rows:
                        if r.name == sortfield:
                            try:
                                query.order_by(r.field_name).query.__str__()
                                if direction.strip() != "desc":
                                    sortargs.append(r.field_name)
                                else:
                                    sortargs.append("-%s" % r.field_name)
                            except Exception:
                                # Can't sort on this field
                                pass
                            break
            if sortargs:
                return query.order_by(
                    "key", *sortargs
                )  # The extra ordering by the 'key' is only change with the default method
            else:
                return query.order_by(
                    "key"
                )  # The extra ordering by the 'key' is only change with the default method

    @staticmethod
    def query(request, basequery, sortsql="1 asc"):
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)
        # Build the query
        query = """
      with combinations as (%s)
      select row_to_json(data)
      from (
      select
        -- Key field
        combinations.key as key,
        -- Attribute fields of item, location and supplier
        combinations.item_id as item,
        item.description as item__description,
        item.category as item__category,
        item.subcategory as item__subcategory,
        item.cost as item__cost,
        item.owner_id as item__owner,
        item.source as item__source,
        item.lastmodified as item__lastmodified,
        combinations.origin_id as origin,
        origin.description as origin__description,
        origin.category as origin__category,
        origin.subcategory as origin__subcategory,
        origin.available_id as origin__available,
        origin.lastmodified as origin__lastmodified,
        combinations.destination_id as destination,
        destination.description as destination__description,
        destination.category as destination__category,
        destination.subcategory as destination__subcategory,
        destination.available_id as destination__available,
        destination.lastmodified as destination__lastmodified,
        -- Buckets
        res.bucket as bucket,
        to_char(res.startdate, 'YYYY-MM-DD') as startdate,
        to_char(res.enddate, 'YYYY-MM-DD') as enddate,
        -- Values
        res.proposed_start as proposed_start,
        res.total_start as total_start,
        res.proposed_end as proposed_end,
        res.total_end as total_end,
        res.proposed_in_transit as proposed_in_transit,
        res.total_in_transit as total_in_transit
      from combinations
      inner join item on combinations.item_id = item.name
      left outer join location origin on combinations.origin_id = origin.name
      left outer join location destination on combinations.destination_id = destination.name
      inner join (
        select
          operationplan.item_id, operationplan.origin_id, operationplan.destination_id,
          d.bucket, d.startdate, d.enddate,
          coalesce(sum(
            case when operationplan.status = 'proposed'
              and d.startdate <= operationplan.startdate and d.enddate > operationplan.startdate
            then operationplan.quantity
            else 0 end
            ), 0) proposed_start,
          coalesce(sum(
            case when d.startdate <= operationplan.startdate and d.enddate > operationplan.startdate
            then operationplan.quantity else 0 end
            ), 0) total_start,
          coalesce(sum(
            case when operationplan.status = 'proposed'
              and d.startdate <= operationplan.enddate and d.enddate > operationplan.enddate
             then operationplan.quantity else 0 end
            ), 0) proposed_end,
          coalesce(sum(
            case when d.startdate <= operationplan.enddate and d.enddate > operationplan.enddate
            then operationplan.quantity else 0 end
            ), 0) total_end,
          coalesce(sum(
            case when operationplan.status = 'proposed'
              and d.enddate > operationplan.startdate and d.enddate <= operationplan.enddate
             then operationplan.quantity else 0 end
            ), 0) proposed_in_transit,
          coalesce(sum(
            case when d.enddate > operationplan.startdate and d.enddate <= operationplan.enddate
            then operationplan.quantity else 0 end
            ), 0) total_in_transit
        from operationplan
        inner join combinations
        on operationplan.item_id = combinations.item_id
          and operationplan.origin_id = combinations.origin_id
          and operationplan.destination_id = combinations.destination_id
        cross join (
          select name as bucket, startdate, enddate
          from common_bucketdetail
          where bucket_id = '%s' and enddate > '%s' and startdate < '%s'
          ) d
        where operationplan.type = 'DO'
        group by operationplan.item_id, operationplan.origin_id, operationplan.destination_id,
          d.bucket, d.startdate, d.enddate
        ) res
      on res.item_id = combinations.item_id
        and res.origin_id = combinations.origin_id
        and res.destination_id = combinations.destination_id
      order by %s, res.startdate
      ) data
      """ % (
            basesql,
            request.report_bucket,
            request.report_startdate,
            request.report_enddate,
            sortsql,
        )

        # Convert the SQL results to Python
        with connections[request.database].chunked_cursor() as cursor_chunked:
            cursor_chunked.execute(query, baseparams)
            for row in cursor_chunked:
                yield row[0]
コード例 #22
0
class DistributionReport(GridPivot):
    '''
  A report summarizing all distribution orders.
  '''
    template = 'output/distribution_order_summary.html'
    title = _('Distribution order summary')
    model = DistributionOrder
    help_url = 'user-guide/user-interface/plan-analysis/distribution-order-summary.html'

    rows = (
        GridFieldText('key',
                      key=True,
                      search=False,
                      initially_hidden=True,
                      hidden=True,
                      field_name="item__name",
                      editable=False),
        GridFieldText('item',
                      title=_('item'),
                      editable=False,
                      field_name='item__name',
                      formatter='detail',
                      extra='"role":"input/item"'),
        GridFieldText('item__description',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('description'))),
        GridFieldText('item__category',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('category'))),
        GridFieldText('item__subcategory',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('subcategory'))),
        GridFieldCurrency('item__cost',
                          initially_hidden=True,
                          editable=False,
                          title=string_concat(_('item'), ' - ', _('cost')),
                          field_name='item__cost'),
        GridFieldText('item__owner',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('owner')),
                      field_name='item__owner__name'),
        GridFieldText('item__source',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('source'))),
        GridFieldLastModified('item__lastmodified',
                              initially_hidden=True,
                              editable=False,
                              title=string_concat(_('item'), ' - ',
                                                  _('last modified'))),
        GridFieldText('origin',
                      title=_('origin'),
                      editable=False,
                      field_name='origin__name',
                      formatter='detail',
                      extra='"role":"input/location"'),
        GridFieldText('origin__description',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('origin'), ' - ',
                                          _('description'))),
        GridFieldText('origin__category',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('origin'), ' - ', _('category'))),
        GridFieldText('origin__subcategory',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('origin'), ' - ',
                                          _('subcategory'))),
        GridFieldText('origin__available',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('origin'), ' - ', _('available')),
                      field_name='origin__available__name',
                      formatter='detail',
                      extra='"role":"input/calendar"'),
        GridFieldLastModified('origin__lastmodified',
                              initially_hidden=True,
                              editable=False,
                              title=string_concat(_('origin'), ' - ',
                                                  _('last modified'))),
        GridFieldText('destination',
                      title=_('destination'),
                      editable=False,
                      field_name='destination__name',
                      formatter='detail',
                      extra='"role":"input/location"'),
        GridFieldText('destination__description',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('destination'), ' - ',
                                          _('description'))),
        GridFieldText('destination__category',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('destination'), ' - ',
                                          _('category'))),
        GridFieldText('destination__subcategory',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('destination'), ' - ',
                                          _('subcategory'))),
        GridFieldText('destination__available',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('destination'), ' - ',
                                          _('available')),
                      field_name='destination__available__name',
                      formatter='detail',
                      extra='"role":"input/calendar"'),
        GridFieldLastModified('destination__lastmodified',
                              initially_hidden=True,
                              editable=False,
                              title=string_concat(_('destination'), ' - ',
                                                  _('last modified'))),
    )

    crosses = (
        ('proposed_start', {
            'title': _('proposed shipping')
        }),
        ('total_start', {
            'title': _('total shipping')
        }),
        ('proposed_end', {
            'title': _('proposed receiving')
        }),
        ('total_end', {
            'title': _('total receiving')
        }),
        ('proposed_in_transit', {
            'title': _('proposed in transit')
        }),
        ('total_in_transit', {
            'title': _('total in transit')
        }),
    )

    @staticmethod
    def basequeryset(request, *args, **kwargs):
        current, start, end = getHorizon(request)
        return DistributionOrder.objects.all() \
          .filter(startdate__lte=end, enddate__gte=start) \
          .distinct('item', 'origin', 'destination') \
          .order_by()   # Ordering isn't compatible with the distinct

    @staticmethod
    def query(request, basequery, sortsql='1 asc'):
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)
        # Build the query
        query = '''
      with combinations as (%s)
      select row_to_json(data)
      from (
      select
        -- Key field
        combinations.item_id || combinations.origin_id || combinations.destination_id as key,
        -- Attribute fields of item, location and supplier
        combinations.item_id as item,
        item.description as item__description,
        item.category as item__category,
        item.subcategory as item__subcategory,
        item.cost as item__cost,
        item.owner_id as item__owner,
        item.source as item__source,
        item.lastmodified as item__lastmodified,
        combinations.origin_id as origin,
        origin.description as origin__description,
        origin.category as origin__category,
        origin.subcategory as origin__subcategory,
        origin.available_id as origin__available,
        origin.lastmodified as origin__lastmodified,
        combinations.destination_id as destination,
        destination.description as destination__description,
        destination.category as destination__category,
        destination.subcategory as destination__subcategory,
        destination.available_id as destination__available,
        destination.lastmodified as destination__lastmodified,
        -- Buckets
        res.bucket as bucket,
        to_char(res.startdate, 'YYYY-MM-DD') as startdate,
        to_char(res.enddate, 'YYYY-MM-DD') as enddate,
        -- Values
        res.proposed_start as proposed_start,
        res.total_start as total_start,
        res.proposed_end as proposed_end,
        res.total_end as total_end,
        res.proposed_in_transit as proposed_in_transit,
        res.total_in_transit as total_in_transit
      from combinations
      inner join item on combinations.item_id = item.name
      left outer join location origin on combinations.origin_id = origin.name
      left outer join location destination on combinations.destination_id = destination.name
      inner join (
        select
          operationplan.item_id, operationplan.origin_id, operationplan.destination_id,
          d.bucket, d.startdate, d.enddate,
          coalesce(sum(
            case when operationplan.status = 'proposed'
              and d.startdate <= operationplan.startdate and d.enddate > operationplan.startdate
            then operationplan.quantity
            else 0 end
            ), 0) proposed_start,
          coalesce(sum(
            case when d.startdate <= operationplan.startdate and d.enddate > operationplan.startdate
            then operationplan.quantity else 0 end
            ), 0) total_start,
          coalesce(sum(
            case when operationplan.status = 'proposed'
              and d.startdate <= operationplan.enddate and d.enddate > operationplan.enddate
             then operationplan.quantity else 0 end
            ), 0) proposed_end,
          coalesce(sum(
            case when d.startdate <= operationplan.enddate and d.enddate > operationplan.enddate
            then operationplan.quantity else 0 end
            ), 0) total_end,
          coalesce(sum(
            case when operationplan.status = 'proposed'
              and d.enddate > operationplan.startdate and d.enddate <= operationplan.enddate
             then operationplan.quantity else 0 end
            ), 0) proposed_in_transit,
          coalesce(sum(
            case when d.enddate > operationplan.startdate and d.enddate <= operationplan.enddate
            then operationplan.quantity else 0 end
            ), 0) total_in_transit
        from operationplan
        inner join combinations
        on operationplan.item_id = combinations.item_id
          and operationplan.origin_id = combinations.origin_id
          and operationplan.destination_id = combinations.destination_id
        cross join (
          select name as bucket, startdate, enddate
          from common_bucketdetail
          where bucket_id = '%s' and enddate > '%s' and startdate < '%s'
          ) d
        where operationplan.type = 'DO'
        group by operationplan.item_id, operationplan.origin_id, operationplan.destination_id,
          d.bucket, d.startdate, d.enddate
        ) res
      on res.item_id = combinations.item_id
        and res.origin_id = combinations.origin_id
        and res.destination_id = combinations.destination_id
      order by %s, res.startdate
      ) data
      ''' % (basesql, request.report_bucket, request.report_startdate,
             request.report_enddate, sortsql)

        # Convert the SQL results to Python
        with connections[request.database].chunked_cursor() as cursor_chunked:
            cursor_chunked.execute(query, baseparams)
            for row in cursor_chunked:
                yield row[0]
コード例 #23
0
ファイル: resource.py プロジェクト: zhengr/frepple
class OverviewReport(GridPivot):
    """
    A report showing the loading of each resource.
    """

    template = "output/resource.html"
    title = _("Resource report")
    model = Resource
    permissions = (("view_resource_report", "Can view resource report"), )
    editable = False
    help_url = "user-interface/plan-analysis/resource-report.html"

    rows = (
        GridFieldText(
            "resource",
            title=_("resource"),
            key=True,
            editable=False,
            field_name="name",
            formatter="detail",
            extra='"role":"input/resource"',
        ),
        GridFieldText(
            "description",
            title=_("description"),
            editable=False,
            field_name="description",
            initially_hidden=True,
        ),
        GridFieldText(
            "category",
            title=_("category"),
            editable=False,
            field_name="category",
            initially_hidden=True,
        ),
        GridFieldText(
            "subcategory",
            title=_("subcategory"),
            editable=False,
            field_name="subcategory",
            initially_hidden=True,
        ),
        GridFieldText(
            "type",
            title=_("type"),
            editable=False,
            field_name="type",
            initially_hidden=True,
        ),
        GridFieldBool(
            "constrained",
            title=_("constrained"),
            editable=False,
            field_name="constrained",
            initially_hidden=True,
        ),
        GridFieldNumber(
            "maximum",
            title=_("maximum"),
            editable=False,
            field_name="maximum",
            initially_hidden=True,
        ),
        GridFieldText(
            "maximum_calendar",
            title=_("maximum calendar"),
            editable=False,
            field_name="maximum_calendar__name",
            formatter="detail",
            extra='"role":"input/calendar"',
            initially_hidden=True,
        ),
        GridFieldCurrency(
            "cost",
            title=_("cost"),
            editable=False,
            field_name="cost",
            initially_hidden=True,
        ),
        GridFieldDuration(
            "maxearly",
            title=_("maxearly"),
            editable=False,
            field_name="maxearly",
            initially_hidden=True,
        ),
        GridFieldText(
            "setupmatrix",
            title=_("setupmatrix"),
            editable=False,
            field_name="setupmatrix__name",
            formatter="detail",
            extra='"role":"input/setupmatrix"',
            initially_hidden=True,
        ),
        GridFieldText(
            "setup",
            title=_("setup"),
            editable=False,
            field_name="setup",
            initially_hidden=True,
        ),
        GridFieldText(
            "location__name",
            title=_("location"),
            editable=False,
            field_name="location__name",
            formatter="detail",
            extra='"role":"input/location"',
        ),
        GridFieldText(
            "location__description",
            title=format_lazy("{} - {}", _("location"), _("description")),
            editable=False,
            initially_hidden=True,
        ),
        GridFieldText(
            "location__category",
            title=format_lazy("{} - {}", _("location"), _("category")),
            editable=False,
            initially_hidden=True,
        ),
        GridFieldText(
            "location__subcategory",
            title=format_lazy("{} - {}", _("location"), _("subcategory")),
            editable=False,
            initially_hidden=True,
        ),
        GridFieldText(
            "location__available",
            title=format_lazy("{} - {}", _("location"), _("available")),
            editable=False,
            field_name="location__available__name",
            formatter="detail",
            extra='"role":"input/calendar"',
            initially_hidden=True,
        ),
        GridFieldNumber(
            "avgutil",
            title=_("utilization %"),
            formatter="percentage",
            editable=False,
            width=100,
            align="center",
        ),
        GridFieldText(
            "available_calendar",
            title=_("available calendar"),
            editable=False,
            field_name="available__name",
            formatter="detail",
            extra='"role":"input/calendar"',
            initially_hidden=True,
        ),
        GridFieldText(
            "owner",
            title=_("owner"),
            editable=False,
            field_name="owner__name",
            formatter="detail",
            extra='"role":"input/resource"',
            initially_hidden=True,
        ),
    )
    crosses = (
        ("available", {
            "title": _("available")
        }),
        ("unavailable", {
            "title": _("unavailable"),
            "initially_hidden": True
        }),
        ("setuptime", {
            "title": _("setup"),
            "initially_hidden": True
        }),
        ("load", {
            "title": _("load")
        }),
        ("utilization", {
            "title": _("utilization %")
        }),
    )

    @classmethod
    def initialize(reportclass, request):
        if reportclass._attributes_added != 2:
            reportclass._attributes_added = 2
            reportclass.attr_sql = ""
            # Adding custom resource attributes
            for f in getAttributeFields(Resource, initially_hidden=True):
                f.editable = False
                reportclass.rows += (f, )
                reportclass.attr_sql += "res.%s, " % f.name.split("__")[-1]
            # Adding custom location attributes
            for f in getAttributeFields(Location,
                                        related_name_prefix="location",
                                        initially_hidden=True):
                f.editable = False
                reportclass.rows += (f, )
                reportclass.attr_sql += "location.%s, " % f.name.split(
                    "__")[-1]

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session["lasttab"] = "plan"
            return {
                "units": reportclass.getUnits(request),
                "title":
                force_str(Resource._meta.verbose_name) + " " + args[0],
                "post_title": _("plan"),
                "model": Resource,
            }
        else:
            return {"units": reportclass.getUnits(request)}

    @classmethod
    def basequeryset(reportclass, request, *args, **kwargs):
        if args and args[0]:
            queryset = Resource.objects.filter(name=args[0])
        else:
            queryset = Resource.objects.all()
        return queryset.annotate(avgutil=RawSQL(
            """
          select ( coalesce(sum(out_resourceplan.load),0) + coalesce(sum(out_resourceplan.setup),0) )
             * 100.0 / coalesce(greatest(sum(out_resourceplan.available), 0.0001),1) as avg_util
          from out_resourceplan
          where out_resourceplan.startdate >= %s
          and out_resourceplan.startdate < %s
          and out_resourceplan.resource = resource.name
          """,
            (request.report_startdate, request.report_enddate),
        ))

    @classmethod
    def getUnits(reportclass, request):
        try:
            units = Parameter.objects.using(
                request.database).get(name="loading_time_units")
            if units.value == "hours":
                return (1.0, _("hours"))
            elif units.value == "weeks":
                return (168, _("weeks"))
            else:
                return (24, _("days"))
        except Exception:
            return (24, _("days"))

    @classmethod
    def query(reportclass, request, basequery, sortsql="1 asc"):
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)

        # Get the time units
        units = OverviewReport.getUnits(request)

        # Assure the item hierarchy is up to date
        Resource.rebuildHierarchy(database=basequery.db)

        # Execute the query
        query = """
      select res.name, res.description, res.category, res.subcategory,
        res.type, res.constrained, res.maximum, res.maximum_calendar_id,
        res.cost, res.maxearly, res.setupmatrix_id, res.setup, location.name,
        location.description, location.category, location.subcategory,
        location.available_id, res.avgutil, res.available_id available_calendar,
        res.owner_id,
        %s
        d.bucket as col1, d.startdate as col2,
        coalesce(sum(out_resourceplan.available),0) / (case when res.type = 'buckets' then 1 else %f end) as available,
        coalesce(sum(out_resourceplan.unavailable),0) / (case when res.type = 'buckets' then 1 else %f end) as unavailable,
        coalesce(sum(out_resourceplan.load),0) / (case when res.type = 'buckets' then 1 else %f end) as loading,
        coalesce(sum(out_resourceplan.setup),0) / (case when res.type = 'buckets' then 1 else %f end) as setup
      from (%s) res
      left outer join location
        on res.location_id = location.name
      -- 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
      -- Utilization info
      left join out_resourceplan
      on res.name = out_resourceplan.resource
      and d.startdate <= out_resourceplan.startdate
      and d.enddate > out_resourceplan.startdate
      and out_resourceplan.startdate >= '%s'
      and out_resourceplan.startdate < '%s'
      -- Grouping and sorting
      group by res.name, res.description, res.category, res.subcategory,
        res.type, res.maximum, res.maximum_calendar_id, res.available_id, res.cost, res.maxearly,
        res.setupmatrix_id, res.setup, location.name, location.description,
        location.category, location.subcategory, location.available_id, res.avgutil, res.owner_id,
        res.constrained,
        %s d.bucket, d.startdate
      order by %s, d.startdate
      """ % (
            reportclass.attr_sql,
            units[0],
            units[0],
            units[0],
            units[0],
            basesql,
            request.report_bucket,
            request.report_startdate,
            request.report_enddate,
            request.report_startdate,
            request.report_enddate,
            reportclass.attr_sql,
            sortsql,
        )

        # Build the python result
        with transaction.atomic(using=request.database):
            with connections[
                    request.database].chunked_cursor() as cursor_chunked:
                cursor_chunked.execute(query, baseparams)
                resourceattributefields = getAttributeFields(Resource)
                locationattributefields = getAttributeFields(Location)
                for row in cursor_chunked:
                    numfields = len(row)
                    if row[numfields - 4] != 0:
                        util = round(
                            row[numfields - 2] * 100 / row[numfields - 4], 2)
                    else:
                        util = 0
                    result = {
                        "resource": row[0],
                        "description": row[1],
                        "category": row[2],
                        "subcategory": row[3],
                        "type": row[4],
                        "constrained": row[5],
                        "maximum": row[6],
                        "maximum_calendar": row[7],
                        "cost": row[8],
                        "maxearly": row[9],
                        "setupmatrix": row[10],
                        "setup": row[11],
                        "location__name": row[12],
                        "location__description": row[13],
                        "location__category": row[14],
                        "location__subcategory": row[15],
                        "location__available": row[16],
                        "avgutil": round(row[17], 2),
                        "available_calendar": row[18],
                        "owner": row[19],
                        "bucket": row[numfields - 6],
                        "startdate": row[numfields - 5],
                        "available": row[numfields - 4],
                        "unavailable": row[numfields - 3],
                        "load": row[numfields - 2],
                        "setuptime": row[numfields - 1],
                        "utilization": util,
                    }
                    idx = 20
                    for f in resourceattributefields:
                        result[f.field_name] = row[idx]
                        idx += 1
                    for f in locationattributefields:
                        result[f.field_name] = row[idx]
                        idx += 1
                    yield result
コード例 #24
0
ファイル: demand.py プロジェクト: xzflin/frePPLe
class DetailReport(GridReport):
    '''
  A list report to show delivery plans for demand.
  '''
    template = 'output/demandplan.html'
    title = _("Demand plan detail")
    model = DeliveryOrder
    basequeryset = DeliveryOrder.objects.all()
    permissions = (("view_demand_report", "Can view demand report"), )
    frozenColumns = 0
    editable = False
    multiselect = False
    help_url = 'user-guide/user-interface/plan-analysis/demand-detail-report.html'
    rows = (
        GridFieldInteger('id',
                         title=_('id'),
                         key=True,
                         editable=False,
                         hidden=True),
        GridFieldText('demand',
                      title=_('demand'),
                      field_name="demand__name",
                      editable=False,
                      formatter='detail',
                      extra="role:'input/demand'"),
        GridFieldText('item',
                      title=_('item'),
                      field_name='demand__item',
                      editable=False,
                      formatter='detail',
                      extra="role:'input/item'"),
        GridFieldText('customer',
                      title=_('customer'),
                      field_name='demand__customer',
                      editable=False,
                      formatter='detail',
                      extra="role:'input/customer'"),
        GridFieldText('location',
                      title=_('location'),
                      field_name='demand__location',
                      editable=False,
                      formatter='detail',
                      extra="role:'input/location'"),
        GridFieldNumber('quantity', title=_('quantity'), editable=False),
        GridFieldNumber('demandquantity',
                        title=_('demand quantity'),
                        field_name='demand__quantity',
                        editable=False),
        GridFieldDateTime('startdate', title=_('start date'), editable=False),
        GridFieldDateTime('enddate', title=_('end date'), editable=False),
        GridFieldDateTime('due',
                          field_name='demand__due',
                          title=_('due date'),
                          editable=False),
    )

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session['lasttab'] = 'plandetail'
        return {'active_tab': 'plandetail'}
コード例 #25
0
class DetailReport(OperationPlanMixin, GridReport):
    '''
  A list report to show OperationPlanResources.
  '''
    template = 'input/operationplanreport.html'
    title = _("Resource detail report")
    model = OperationPlanResource
    permissions = (("view_resource_report", "Can view resource report"), )
    frozenColumns = 3
    editable = False
    multiselect = False
    height = 250
    help_url = 'user-guide/user-interface/plan-analysis/resource-detail-report.html'

    @classmethod
    def basequeryset(reportclass, request, *args, **kwargs):
        if args and args[0]:
            try:
                res = Resource.objects.using(
                    request.database).get(name__exact=args[0])
                base = OperationPlanResource.objects.filter(
                    resource__lft__gte=res.lft, resource__rght__lte=res.rght)
            except OperationPlanResource.DoesNotExist:
                base = OperationPlanResource.objects.filter(
                    resource__exact=args[0])
        else:
            base = OperationPlanResource.objects
        base = reportclass.operationplanExtraBasequery(base, request)
        return base.select_related().extra(
            select={
                'opplan_duration':
                "(operationplan.enddate - operationplan.startdate)",
                'setup_end':
                "(operationplan.plan->>'setupend')",
                'setup_duration':
                "(operationplan.plan->>'setup')",
                'feasible':
                "coalesce((operationplan.plan->>'feasible')::boolean, true)"
            })

    @classmethod
    def initialize(reportclass, request):
        if reportclass._attributes_added != 2:
            reportclass._attributes_added = 2
            # Adding custom operation attributes
            for f in getAttributeFields(
                    Operation, related_name_prefix="operationplan__operation"):
                f.editable = False
                reportclass.rows += (f, )
            # Adding custom resource attributes
            for f in getAttributeFields(Resource,
                                        related_name_prefix="resource"):
                f.editable = False
                reportclass.rows += (f, )

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session['lasttab'] = 'plandetail'
            return {
                'active_tab': 'plandetail',
                'model': Resource,
                'title':
                force_text(Resource._meta.verbose_name) + " " + args[0],
                'post_title': _('plan detail')
            }
        else:
            return {'active_tab': 'plandetail', 'model': None}

    rows = (
        GridFieldInteger('id',
                         title='internal id',
                         key=True,
                         editable=False,
                         hidden=True),
        GridFieldText('resource',
                      title=_('resource'),
                      field_name='resource__name',
                      editable=False,
                      formatter='detail',
                      extra='"role":"input/resource"'),
        GridFieldInteger('operationplan__id',
                         title=_('identifier'),
                         editable=False),
        GridFieldText('operationplan__reference',
                      title=_('reference'),
                      editable=False),
        GridFieldText(
            'operationplan__color',
            title=_('inventory status'),
            formatter='color',
            width='125',
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"'),
        GridFieldText('operationplan__operation__item',
                      title=_('item'),
                      editable=False,
                      formatter='detail',
                      extra='"role":"input/item"'),
        GridFieldText('operationplan__operation__location',
                      title=_('location'),
                      editable=False,
                      formatter='detail',
                      extra='"role":"input/location"'),
        GridFieldText('operationplan__operation__name',
                      title=_('operation'),
                      editable=False,
                      formatter='detail',
                      extra='"role":"input/operation"'),
        GridFieldText('operationplan__operation__description',
                      title=string_concat(_('operation'), ' - ',
                                          _('description')),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('operationplan__operation__category',
                      title=string_concat(_('operation'), ' - ',
                                          _('category')),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('operationplan__operation__subcategory',
                      title=string_concat(_('operation'), ' - ',
                                          _('subcategory')),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('operationplan__operation__type',
                      title=string_concat(_('operation'), ' - ', _('type')),
                      initially_hidden=True),
        GridFieldDuration('operationplan__operation__duration',
                          title=string_concat(_('operation'), ' - ',
                                              _('duration')),
                          initially_hidden=True),
        GridFieldDuration('operationplan__operation__duration_per',
                          title=string_concat(_('operation'), ' - ',
                                              _('duration per unit')),
                          initially_hidden=True),
        GridFieldDuration('operationplan__operation__fence',
                          title=string_concat(_('operation'), ' - ',
                                              _('release fence')),
                          initially_hidden=True),
        GridFieldDuration('operationplan__operation__posttime',
                          title=string_concat(_('operation'), ' - ',
                                              _('post-op time')),
                          initially_hidden=True),
        GridFieldNumber('operationplan__operation__sizeminimum',
                        title=string_concat(_('operation'), ' - ',
                                            _('size minimum')),
                        initially_hidden=True),
        GridFieldNumber('operationplan__operation__sizemultiple',
                        title=string_concat(_('operation'), ' - ',
                                            _('size multiple')),
                        initially_hidden=True),
        GridFieldNumber('operationplan__operation__sizemaximum',
                        title=string_concat(_('operation'), ' - ',
                                            _('size maximum')),
                        initially_hidden=True),
        GridFieldInteger('operationplan__operation__priority',
                         title=string_concat(_('operation'), ' - ',
                                             _('priority')),
                         initially_hidden=True),
        GridFieldDateTime('operationplan__operation__effective_start',
                          title=string_concat(_('operation'), ' - ',
                                              _('effective start')),
                          initially_hidden=True),
        GridFieldDateTime('operationplan__operation__effective_end',
                          title=string_concat(_('operation'), ' - ',
                                              _('effective end')),
                          initially_hidden=True),
        GridFieldCurrency('operationplan__operation__cost',
                          title=string_concat(_('operation'), ' - ',
                                              _('cost')),
                          initially_hidden=True),
        GridFieldText('operationplan__operation__search',
                      title=string_concat(_('operation'), ' - ',
                                          _('search mode')),
                      initially_hidden=True),
        GridFieldText('operationplan__operation__source',
                      title=string_concat(_('operation'), ' - ', _('source')),
                      initially_hidden=True),
        GridFieldLastModified('operationplan__operation__lastmodified',
                              title=string_concat(_('operation'), ' - ',
                                                  _('last modified')),
                              initially_hidden=True),
        GridFieldDateTime(
            'operationplan__startdate',
            title=_('start date'),
            editable=False,
            extra=
            '"formatoptions":{"srcformat":"Y-m-d H:i:s","newformat":"Y-m-d H:i:s", "defaultValue":""}, "summaryType":"min"'
        ),
        GridFieldDateTime(
            'operationplan__enddate',
            title=_('end date'),
            editable=False,
            extra=
            '"formatoptions":{"srcformat":"Y-m-d H:i:s","newformat":"Y-m-d H:i:s", "defaultValue":""}, "summaryType":"max"'
        ),
        GridFieldDuration(
            'opplan_duration',
            title=_('duration'),
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"sum"'),
        GridFieldNumber(
            'operationplan__quantity',
            title=_('quantity'),
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"sum"'),
        GridFieldText('operationplan__status',
                      title=_('status'),
                      editable=False),
        GridFieldNumber(
            'operationplan__criticality',
            title=_('criticality'),
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"min"'),
        GridFieldDuration(
            'operationplan__delay',
            title=_('delay'),
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"max"'),
        GridFieldText('demand',
                      title=_('demands'),
                      formatter='demanddetail',
                      extra='"role":"input/demand"',
                      width=300,
                      editable=False,
                      sortable=False),
        GridFieldText('operationplan__type',
                      title=_('type'),
                      field_name='operationplan__type',
                      editable=False),
        GridFieldNumber(
            'quantity',
            title=_('load quantity'),
            editable=False,
            extra='"formatoptions":{"defaultValue":""}, "summaryType":"sum"'),
        GridFieldText('setup',
                      title=_('setup'),
                      editable=False,
                      initially_hidden=True),
        GridFieldDateTime('setup_end',
                          title=_('setup end date'),
                          editable=False,
                          initially_hidden=True),
        GridFieldDuration('setup_duration',
                          title=_('setup duration'),
                          editable=False,
                          initially_hidden=True),
        GridFieldBool('feasible',
                      title=_('feasible'),
                      editable=False,
                      initially_hidden=True,
                      search=False),
        # Optional fields referencing the item
        GridFieldText('operationplan__operation__item__description',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('description'))),
        GridFieldText('operationplan__operation__item__category',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('category'))),
        GridFieldText('operationplan__operation__item__subcategory',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('subcategory'))),
        GridFieldText(
            'operationplan__operation__item__owner',
            initially_hidden=True,
            editable=False,
            title=string_concat(_('item'), ' - ', _('owner')),
            field_name='operationplan__operation__item__owner__name'),
        GridFieldText('operationplan__operation__item__source',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('source'))),
        GridFieldLastModified(
            'operationplan__operation__item__lastmodified',
            initially_hidden=True,
            editable=False,
            title=string_concat(_('item'), ' - ', _('last modified')),
        ),
        # Optional fields referencing the operation location
        GridFieldText('operationplan__operation__location__description',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('location'), ' - ',
                                          _('description'))),
        GridFieldText('operationplan__operation__location__category',
                      title=string_concat(_('location'), ' - ', _('category')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('operationplan__operation__location__subcategory',
                      title=string_concat(_('location'), ' - ',
                                          _('subcategory')),
                      initially_hidden=True,
                      editable=False),
        GridFieldText(
            'operationplan__operation__location__available',
            editable=False,
            title=string_concat(_('location'), ' - ', _('available')),
            initially_hidden=True,
            field_name='operationplan__operation__location__available__name',
            formatter='detail',
            extra='"role":"input/calendar"'),
        GridFieldText(
            'operationplan__operation__location__owner',
            initially_hidden=True,
            title=string_concat(_('location'), ' - ', _('owner')),
            field_name='operationplan__operation__location__owner__name',
            formatter='detail',
            extra='"role":"input/location"',
            editable=False),
        GridFieldText('operationplan__operation__location__source',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('location'), ' - ', _('source'))),
        GridFieldLastModified(
            'operationplan__operation__location__lastmodified',
            initially_hidden=True,
            editable=False,
            title=string_concat(_('location'), ' - ', _('last modified'))),
        # Optional fields referencing the resource
        GridFieldText('resource__description',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('resource'), ' - ',
                                          _('description'))),
        GridFieldText('resource__category',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('resource'), ' - ',
                                          _('category'))),
        GridFieldText('resource__subcategory',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('resource'), ' - ',
                                          _('subcategory'))),
        GridFieldText('resource__type',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('resource'), ' - ', _('type'))),
        GridFieldNumber('resource__maximum',
                        editable=False,
                        initially_hidden=True,
                        title=string_concat(_('resource'), ' - ',
                                            _('maximum'))),
        GridFieldText('resource__maximum_calendar',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('resource'), ' - ',
                                          _('maximum calendar')),
                      field_name='resource__maximum_calendar__name',
                      formatter='detail',
                      extra='"role":"input/calendar"'),
        GridFieldCurrency('resource__cost',
                          editable=False,
                          initially_hidden=True,
                          title=string_concat(_('resource'), ' - ',
                                              _('cost'))),
        GridFieldDuration('resource__maxearly',
                          editable=False,
                          initially_hidden=True,
                          title=string_concat(_('resource'), ' - ',
                                              _('maxearly'))),
        GridFieldText('resource__setupmatrix',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('resource'), ' - ',
                                          _('setupmatrix')),
                      field_name='resource__setupmatrix__name',
                      formatter='detail',
                      extra='"role":"input/setupmatrix"'),
        GridFieldText('resource__setup',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('resource'), ' - ', _('setup'))),
        GridFieldText('resource_location',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('resource'), ' - ', _('location')),
                      field_name='resource__location__name',
                      formatter='detail',
                      extra='"role":"input/location"'),
        # Optional fields referencing the resource location
        GridFieldText('resource__location__description',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('resource'), ' - ', _('location'),
                                          ' - ', _('description'))),
        GridFieldText('resource__location__category',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('resource'), ' - ', _('location'),
                                          ' - ', _('category'))),
        GridFieldText('resource__location__subcategory',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('resource'), ' - ', _('location'),
                                          ' - ', _('subcategory'))),
        GridFieldText('resource__location__available',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('resource'), ' - ', _('location'),
                                          ' - ', _('available')),
                      field_name='resource__location__available__name',
                      formatter='detail',
                      extra='"role":"input/calendar"'),
        GridFieldText('resource__location__owner',
                      extra='"role":"input/location"',
                      editable=False,
                      title=string_concat(_('resource'), ' - ', _('location'),
                                          ' - ', _('owner')),
                      initially_hidden=True,
                      field_name='resource__location__owner__name',
                      formatter='detail'),
        GridFieldText('resource__location__source',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('resource'), ' - ', _('location'),
                                          ' - ', _('source'))),
        GridFieldLastModified('resource__location__lastmodified',
                              initially_hidden=True,
                              editable=False,
                              title=string_concat(_('resource'), ' - ',
                                                  _('location'), ' - ',
                                                  _('last modified'))),
    )
コード例 #26
0
ファイル: demand.py プロジェクト: xzflin/frePPLe
class OverviewReport(GridPivot):
    '''
  A report showing the independent demand for each item.
  '''
    template = 'output/demand.html'
    title = _('Demand report')
    basequeryset = Item.objects.all()
    model = Item
    permissions = (("view_demand_report", "Can view demand report"), )
    rows = (GridFieldText('item',
                          title=_('item'),
                          key=True,
                          editable=False,
                          field_name='name',
                          formatter='detail',
                          extra="role:'input/item'"), )
    crosses = (
        ('demand', {
            'title': _('demand')
        }),
        ('supply', {
            'title': _('supply')
        }),
        ('backlog', {
            'title': _('backlog')
        }),
    )

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session['lasttab'] = 'plan'
            return {
                'title':
                capfirst(force_text(Item._meta.verbose_name) + " " + args[0]),
                'post_title':
                ': ' + capfirst(force_text(_('plan'))),
            }
        else:
            return {}

    @staticmethod
    def query(request, basequery, sortsql='1 asc'):
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)
        cursor = connections[request.database].cursor()

        # Assure the item hierarchy is up to date
        Item.rebuildHierarchy(database=basequery.db)

        # Execute a query to get the backlog at the start of the horizon
        startbacklogdict = {}
        query = '''
      select items.name, coalesce(req.qty, 0) - coalesce(pln.qty, 0)
      from (%s) items
      left outer join (
        select item_id, sum(quantity) qty
        from demand
        where status in ('open', 'quote')
        and due < %%s
        group by item_id
        ) req
      on req.item_id = items.name
      left outer join (
        select demand.item_id, sum(operationplan.quantity) qty
        from operationplan
        inner join demand
        on operationplan.demand_id = demand.name
        and operationplan.owner_id is null
        and operationplan.enddate < %%s
        group by demand.item_id
        ) pln
      on pln.item_id = items.name
      ''' % basesql
        cursor.execute(
            query,
            baseparams + (request.report_startdate, request.report_startdate))
        for row in cursor.fetchall():
            if row[0]:
                startbacklogdict[row[0]] = float(row[1])

        # Execute the query
        query = '''
        select y.name as row1,
               y.bucket as col1, y.startdate as col2, y.enddate as col3,
               min(y.orders),
               min(y.planned)
        from (
          select x.name as name, x.lft as lft, x.rght as rght,
               x.bucket as bucket, x.startdate as startdate, x.enddate as enddate,
               coalesce(sum(demand.quantity),0) as orders,
               min(x.planned) as planned
          from (
          select items.name as name, items.lft as lft, items.rght as rght,
                 d.bucket as bucket, d.startdate as startdate, d.enddate as enddate,
                 coalesce(sum(operationplan.quantity),0) as planned
          from (%s) items
          -- 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
          -- Include hierarchical children
          inner join item
          on item.lft between items.lft and items.rght
          -- Planned quantity
          left outer join demand
          on item.name = demand.item_id
          left outer join operationplan
          on demand.name = operationplan.demand_id
          and d.startdate <= operationplan.enddate
          and d.enddate > operationplan.enddate
          and operationplan.enddate >= %%s
          and operationplan.enddate < %%s
          and operationplan.owner_id is null
          -- Grouping
          group by items.name, items.lft, items.rght, d.bucket, d.startdate, d.enddate
        ) x
        -- Requested quantity
        inner join item
        on item.lft between x.lft and x.rght
        left join demand
        on item.name = demand.item_id
        and x.startdate <= demand.due
        and x.enddate > demand.due
        and demand.due >= %%s
        and demand.due < %%s
        and demand.status in ('open', 'quote')
        -- Grouping
        group by x.name, x.lft, x.rght, x.bucket, x.startdate, x.enddate
        ) y
        -- Ordering and grouping
        group by y.name, y.lft, y.rght, y.bucket, y.startdate, y.enddate
        order by %s, y.startdate
       ''' % (basesql, sortsql)
        cursor.execute(
            query,
            baseparams + (request.report_bucket, request.report_startdate,
                          request.report_enddate, request.report_startdate,
                          request.report_enddate, request.report_startdate,
                          request.report_enddate))

        # Build the python result
        previtem = None
        for row in cursor.fetchall():
            if row[0] != previtem:
                backlog = startbacklogdict.get(row[0], 0)
                previtem = row[0]
            backlog += float(row[4]) - float(row[5])
            yield {
                'item': row[0],
                'bucket': row[1],
                'startdate': row[2].date(),
                'enddate': row[3].date(),
                'demand': round(row[4], 1),
                'supply': round(row[5], 1),
                'backlog': round(backlog, 1)
            }
コード例 #27
0
ファイル: views.py プロジェクト: gaohaian/frePPLe
class PathReport(GridReport):
    '''
  A report showing the upstream supply path or following downstream a
  where-used path.
  The supply path report shows all the materials, operations and resources
  used to make a certain item.
  The where-used report shows all the materials and operations that use
  a specific item.
  '''
    template = 'input/path.html'
    title = _("Supply path")
    filterable = False
    frozenColumns = 0
    editable = False
    default_sort = None
    multiselect = False
    rows = (
        GridFieldText('depth',
                      title=_('depth'),
                      editable=False,
                      sortable=False),
        GridFieldText('operation',
                      title=_('operation'),
                      formatter='operation',
                      editable=False,
                      sortable=False),
        GridFieldNumber('quantity',
                        title=_('quantity'),
                        editable=False,
                        sortable=False),
        GridFieldText('location',
                      title=_('location'),
                      editable=False,
                      sortable=False),
        GridFieldText('type', title=_('type'), editable=False, sortable=False),
        GridFieldDuration('duration',
                          title=_('duration'),
                          editable=False,
                          sortable=False),
        GridFieldDuration('duration_per',
                          title=_('duration per unit'),
                          editable=False,
                          sortable=False),
        GridFieldText('resources',
                      editable=False,
                      sortable=False,
                      extra='formatter:reslistfmt'),
        GridFieldText('buffers', editable=False, sortable=False, hidden=True),
        GridFieldText('suboperation',
                      editable=False,
                      sortable=False,
                      hidden=True),
        GridFieldText('numsuboperations',
                      editable=False,
                      sortable=False,
                      hidden=True),
        GridFieldText('parentoper',
                      editable=False,
                      sortable=False,
                      hidden=True),
        GridFieldText('realdepth', editable=False, sortable=False,
                      hidden=True),
        GridFieldText('id', editable=False, sortable=False, hidden=True),
        GridFieldText('parent', editable=False, sortable=False, hidden=True),
        GridFieldText('leaf', editable=False, sortable=False, hidden=True),
        GridFieldText('expanded', editable=False, sortable=False, hidden=True),
    )

    # Attributes to be specified by the subclasses
    objecttype = None
    downstream = None

    @classmethod
    def basequeryset(reportclass, request, args, kwargs):
        return reportclass.objecttype.objects.filter(
            name__exact=args[0]).values('name')

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        return {
            'title':
            capfirst(
                force_text(reportclass.objecttype._meta.verbose_name) + " " +
                args[0] + ": " +
                force_text(reportclass.downstream and _("Where Used")
                           or _("Supply Path"))),
            'downstream':
            reportclass.downstream,
            'active_tab':
            reportclass.downstream and 'whereused' or 'supplypath',
            'model':
            reportclass.objecttype.__name__.lower
        }

    @classmethod
    def getRoot(request, entity):
        raise Http404("invalid entity type")

    @classmethod
    def query(reportclass, request, basequery):
        '''
    A function that recurses upstream or downstream in the supply chain.
    '''
        entity = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)[1]
        entity = entity[0]
        root = reportclass.getRoot(request, entity)

        # Recurse over all operations
        counter = 1
        #operations = set()
        while len(root) > 0:
            # Pop the current node from the stack
            level, parent, curoperation, curqty, issuboperation, parentoper, realdepth, pushsuper = root.pop(
            )
            curnode = counter
            counter += 1

            # If an operation has parent operations we forget about the current operation
            # and use only the parent
            if pushsuper:
                hasParents = False
                for x in curoperation.superoperations.using(
                        request.database).only('operation').order_by(
                            "-priority"):
                    root.append((level, parent, x.operation, curqty,
                                 issuboperation, parentoper, realdepth, False))
                    hasParents = True
                if hasParents:
                    continue

            # Avoid showing the same operation twice.
            # This feature is disabled by default a) because it is not intuitive to understand
            # where operations are skipped, and b) because the quantity of each occurrence might
            # be different.
            # In some models the duplication is confusing and you can enable this feature.
            #if curoperation in operations: continue
            #operations.add(curoperation)

            # Find the next level
            hasChildren = False
            subcount = 0
            if reportclass.downstream:
                # Downstream recursion
                for x in curoperation.flows.filter(
                        quantity__gt=0).only('thebuffer').using(
                            request.database):
                    curflows = x.thebuffer.flows.filter(quantity__lt=0).only(
                        'operation', 'quantity').using(request.database)
                    for y in curflows:
                        hasChildren = True
                        root.append((level - 1, curnode, y.operation,
                                     -curqty * y.quantity, subcount, None,
                                     realdepth - 1, pushsuper))
                for x in curoperation.suboperations.using(
                        request.database).only('suboperation').order_by(
                            "-priority"):
                    subcount += curoperation.type == "routing" and 1 or -1
                    root.append((level - 1, curnode, x.suboperation, curqty,
                                 subcount, curoperation, realdepth, False))
                    hasChildren = True
            else:
                # Upstream recursion
                curprodflow = None
                for x in curoperation.flows.filter(
                        quantity__gt=0).only('quantity').using(
                            request.database):
                    curprodflow = x
                curflows = curoperation.flows.filter(quantity__lt=0).only(
                    'thebuffer', 'quantity').using(request.database)
                for y in curflows:
                    if y.thebuffer.producing:
                        hasChildren = True
                        root.append(
                            (level + 1, curnode, y.thebuffer.producing,
                             curprodflow and
                             (-curqty * y.quantity) / curprodflow.quantity
                             or (-curqty * y.quantity), subcount, None,
                             realdepth + 1, True))
                for x in curoperation.suboperations.using(
                        request.database).only('suboperation').order_by(
                            "-priority"):
                    subcount += curoperation.type == "routing" and 1 or -1
                    root.append((level + 1, curnode, x.suboperation, curqty,
                                 subcount, curoperation, realdepth, False))
                    hasChildren = True

            # Process the current node
            yield {
                'depth':
                abs(level),
                'id':
                curnode,
                'operation':
                curoperation.name,
                'type':
                curoperation.type,
                'location':
                curoperation.location and curoperation.location.name or '',
                'duration':
                curoperation.duration,
                'duration_per':
                curoperation.duration_per,
                'quantity':
                curqty,
                'suboperation':
                issuboperation,
                'buffers':
                [(x.thebuffer.name, float(x.quantity))
                 for x in curoperation.flows.only(
                     'thebuffer', 'quantity').using(request.database)],
                'resources':
                [(x.resource.name, float(x.quantity))
                 for x in curoperation.loads.only(
                     'resource', 'quantity').using(request.database)],
                'parentoper':
                parentoper and parentoper.name,
                'parent':
                parent,
                'leaf':
                hasChildren and 'false' or 'true',
                'expanded':
                'true',
                'numsuboperations':
                subcount,
                'realdepth':
                realdepth
            }
コード例 #28
0
class OverviewReport(GridPivot):
    '''
  A report summarizing all manufacturing orders.
  '''
    template = 'output/operation.html'
    title = _('Manufacturing order summary')
    model = Operation
    permissions = (("view_operation_report", "Can view operation report"), )
    help_url = 'user-guide/user-interface/plan-analysis/manufacturing-order-summary.html'

    rows = (
        GridFieldText('operation',
                      title=_('operation'),
                      key=True,
                      editable=False,
                      field_name='name',
                      formatter='detail',
                      extra='"role":"input/operation"'),
        GridFieldText('location',
                      title=_('location'),
                      editable=False,
                      field_name='location__name',
                      formatter='detail',
                      extra='"role":"input/location"'),
        # Optional fields on the operation
        GridFieldText('item',
                      title=_('item'),
                      editable=False,
                      field_name="item__name",
                      formatter='detail',
                      extra='"role":"input/item"',
                      initially_hidden=True),
        GridFieldText('description',
                      title=_('description'),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('category',
                      title=_('category'),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('subcategory',
                      title=_('subcategory'),
                      editable=False,
                      initially_hidden=True),
        GridFieldText('type',
                      title=_('type'),
                      initially_hidden=True,
                      editable=False),
        GridFieldDuration('duration',
                          title=_('duration'),
                          initially_hidden=True,
                          editable=False),
        GridFieldDuration('duration_per',
                          title=_('duration per unit'),
                          initially_hidden=True,
                          editable=False),
        GridFieldDuration('fence',
                          title=_('release fence'),
                          initially_hidden=True,
                          editable=False),
        GridFieldDuration('posttime',
                          title=_('post-op time'),
                          initially_hidden=True,
                          editable=False),
        GridFieldNumber('sizeminimum',
                        title=_('size minimum'),
                        initially_hidden=True,
                        editable=False),
        GridFieldNumber('sizemultiple',
                        title=_('size multiple'),
                        initially_hidden=True,
                        editable=False),
        GridFieldNumber('sizemaximum',
                        title=_('size maximum'),
                        initially_hidden=True,
                        editable=False),
        GridFieldInteger('priority',
                         title=_('priority'),
                         initially_hidden=True,
                         editable=False),
        GridFieldDateTime('effective_start',
                          title=_('effective start'),
                          initially_hidden=True,
                          editable=False),
        GridFieldDateTime('effective_end',
                          title=_('effective end'),
                          initially_hidden=True,
                          editable=False),
        GridFieldCurrency('cost',
                          title=_('cost'),
                          initially_hidden=True,
                          editable=False),
        GridFieldText('search',
                      title=_('search mode'),
                      initially_hidden=True,
                      editable=False),
        GridFieldText('source',
                      title=_('source'),
                      initially_hidden=True,
                      editable=False),
        GridFieldLastModified('lastmodified',
                              initially_hidden=True,
                              editable=False),
        # Optional fields on the location
        GridFieldText('location__description',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('location'), ' - ',
                                          _('description'))),
        GridFieldText('location__category',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('location'), ' - ',
                                          _('category'))),
        GridFieldText('location__subcategory',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('location'), ' - ',
                                          _('subcategory'))),
        GridFieldText('location__available',
                      editable=False,
                      initially_hidden=True,
                      title=string_concat(_('location'), ' - ',
                                          _('available')),
                      field_name='location__available__name',
                      formatter='detail',
                      extra='"role":"input/calendar"'),
        GridFieldLastModified('location__lastmodified',
                              initially_hidden=True,
                              editable=False,
                              title=string_concat(_('location'), ' - ',
                                                  _('last modified'))),
        # Optional fields referencing the item
        GridFieldText('item__description',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('description'))),
        GridFieldText('item__category',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('category'))),
        GridFieldText('item__subcategory',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('subcategory'))),
        GridFieldText('item__owner',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('owner')),
                      field_name='item__owner__name'),
        GridFieldText('item__source',
                      initially_hidden=True,
                      editable=False,
                      title=string_concat(_('item'), ' - ', _('source'))),
        GridFieldLastModified('item__lastmodified',
                              initially_hidden=True,
                              editable=False,
                              title=string_concat(_('item'), ' - ',
                                                  _('last modified'))),
    )

    crosses = (
        ('proposed_start', {
            'title': _('proposed starts')
        }),
        ('total_start', {
            'title': _('total starts')
        }),
        ('proposed_end', {
            'title': _('proposed ends')
        }),
        ('total_end', {
            'title': _('total ends')
        }),
        ('production_proposed', {
            'title': _('proposed production')
        }),
        ('production_total', {
            'title': _('total production')
        }),
    )

    @staticmethod
    def basequeryset(request, *args, **kwargs):
        if args and args[0]:
            request.session['lasttab'] = 'plan'
            return Operation.objects.all()
        else:
            current, start, end = getHorizon(request)
            return Operation.objects.all().extra(where=[
                'exists (select 1 from operationplan where operationplan.operation_id = operation.name and startdate <= %s and enddate >= %s)'
            ],
                                                 params=[end, start])

    @staticmethod
    def extra_context(request, *args, **kwargs):
        if args and args[0]:
            request.session['lasttab'] = 'plan'
            return {
                'title':
                force_text(Operation._meta.verbose_name) + " " + args[0],
                'post_title': _('plan')
            }
        else:
            return {}

    @staticmethod
    def query(request, basequery, sortsql='1 asc'):
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)
        # Build the query
        query = '''
      select
        operation.name, location.name, operation.item_id, operation.description,
        operation.category, operation.subcategory, operation.type, operation.duration,
        operation.duration_per, operation.fence, operation.posttime, operation.sizeminimum,
        operation.sizemultiple, operation.sizemaximum, operation.priority, operation.effective_start,
        operation.effective_end, operation.cost, operation.search, operation.source, operation.lastmodified,
        location.description, location.category, location.subcategory, location.available_id,
        location.lastmodified, item.description, item.category, item.subcategory, item.owner_id,
        item.source, item.lastmodified,
        res.bucket, res.startdate, res.enddate,
        res.proposed_start, res.total_start, res.proposed_end, res.total_end, res.proposed_production, res.total_production
      from operation
      left outer join item
      on operation.item_id = item.name
      left outer join location
      on operation.location_id = location.name
      inner join (
        select oper.name as operation_id, d.bucket, d.startdate, d.enddate,
         coalesce(sum(
           case when operationplan.status = 'proposed'
             and d.startdate <= operationplan.startdate and d.enddate > operationplan.startdate
           then operationplan.quantity
           else 0 end
           ), 0) proposed_start,
         coalesce(sum(
           case when d.startdate <= operationplan.startdate and d.enddate > operationplan.startdate
           then operationplan.quantity else 0 end
           ), 0) total_start,
         coalesce(sum(
           case when operationplan.status = 'proposed'
             and d.startdate < operationplan.enddate and d.enddate >= operationplan.enddate
           then operationplan.quantity else 0 end
           ), 0) proposed_end,
         coalesce(sum(
           case when d.startdate < operationplan.enddate and d.enddate >= operationplan.enddate
           then operationplan.quantity else 0 end
           ), 0) total_end,
         coalesce(sum(
           case when operationplan.status = 'proposed' then
             (
             -- Total overlap
             extract (epoch from least(operationplan.enddate, d.enddate) - greatest(operationplan.startdate, d.startdate))
             -- Minus the interruptions
             - coalesce((
                select sum(greatest(0, extract (epoch from
                  least(to_timestamp(value->>1, 'YYYY-MM-DD HH24:MI:SS'), d.enddate)
                  - greatest(to_timestamp(value->>0, 'YYYY-MM-DD HH24:MI:SS'), d.startdate)
                  )))
                from ( select * from jsonb_array_elements(plan->'interruptions')) breaks
                ), 0)
             )
             / greatest(1, extract(epoch from operationplan.enddate - operationplan.startdate) - coalesce((plan#>>'{unavailable}')::numeric, 0))
             * operationplan.quantity
           else 0 end
           ), 0) proposed_production,
         coalesce(sum(
             (
             -- Total overlap
             extract (epoch from least(operationplan.enddate, d.enddate) - greatest(operationplan.startdate, d.startdate))
             -- Minus the interruptions
             - coalesce((
                select sum(greatest(0, extract (epoch from
                  least(to_timestamp(value->>1, 'YYYY-MM-DD HH24:MI:SS'), d.enddate)
                  - greatest(to_timestamp(value->>0, 'YYYY-MM-DD HH24:MI:SS'), d.startdate)
                  )))
                from ( select * from jsonb_array_elements(plan->'interruptions')) breaks
                ), 0)
             )
           / greatest(1, extract(epoch from operationplan.enddate - operationplan.startdate) - coalesce((plan#>>'{unavailable}')::numeric, 0))
           * operationplan.quantity
           ), 0) total_production
        from (%s) oper
        -- 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
        -- Match overlapping operationplans
        left outer join operationplan
          on operationplan.operation_id = oper.name
          and (operationplan.startdate, operationplan.enddate) overlaps (d.startdate, d.enddate)
        group by oper.name, d.bucket, d.startdate, d.enddate
      ) res
      on res.operation_id = operation.name
      order by %s, res.startdate
      ''' % (basesql, request.report_bucket, request.report_startdate,
             request.report_enddate, sortsql)

        # Convert the SQl results to Python
        with connections[request.database].chunked_cursor() as cursor_chunked:
            cursor_chunked.execute(query, baseparams)
            for row in cursor_chunked:
                yield {
                    'operation': row[0],
                    'location': row[1],
                    'item': row[2],
                    'description': row[3],
                    'category': row[4],
                    'subcategory': row[5],
                    'type': row[6],
                    'duration': row[7],
                    'duration_per': row[8],
                    'fence': row[9],
                    'posttime': row[10],
                    'sizeminimum': row[11],
                    'sizemultiple': row[12],
                    'sizemaximum': row[13],
                    'priority': row[14],
                    'effective_start': row[15],
                    'effective_end': row[16],
                    'cost': row[17],
                    'search': row[18],
                    'source': row[19],
                    'lastmodified': row[20],
                    'location__description': row[21],
                    'location__category': row[22],
                    'location__subcategory': row[23],
                    'location__available': row[24],
                    'location__lastmodified': row[25],
                    'item__description': row[26],
                    'item__category': row[27],
                    'item__subcategory': row[28],
                    'item__owner': row[29],
                    'item__source': row[30],
                    'item__lastmodified': row[31],
                    'bucket': row[32],
                    'startdate': row[33].date(),
                    'enddate': row[34].date(),
                    'proposed_start': row[35],
                    'total_start': row[36],
                    'proposed_end': row[37],
                    'total_end': row[38],
                    'production_proposed': row[39],
                    'production_total': row[40]
                }
コード例 #29
0
class OverviewReport(GridPivot):
    '''
  A report showing the planned starts of each operation.
  '''
    template = 'output/operation.html'
    title = _('Operation report')
    basequeryset = Operation.objects.all()
    model = Operation
    permissions = (("view_operation_report", "Can view operation report"), )
    rows = (
        GridFieldText('operation',
                      title=_('operation'),
                      key=True,
                      editable=False,
                      field_name='name',
                      formatter='detail',
                      extra="role:'input/operation'"),
        GridFieldText('location',
                      title=_('location'),
                      editable=False,
                      field_name='location__name',
                      formatter='detail',
                      extra="role:'input/location'"),
    )
    crosses = (
        ('locked_start', {
            'title': _('locked starts')
        }),
        ('total_start', {
            'title': _('total starts')
        }),
        ('locked_end', {
            'title': _('locked ends')
        }),
        ('total_end', {
            'title': _('total ends')
        }),
    )

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session['lasttab'] = 'plan'
            return {
                'title':
                capfirst(
                    force_text(Operation._meta.verbose_name) + " " + args[0]),
                'post_title':
                ': ' + capfirst(force_text(_('plan'))),
            }
        else:
            return {}

    @staticmethod
    def query(request, basequery, sortsql='1 asc'):
        basesql, baseparams = basequery.query.get_compiler(
            basequery.db).as_sql(with_col_aliases=False)
        # Run the query
        cursor = connections[request.database].cursor()
        query = '''
        select x.row1, x.row2, x.col1, x.col2, x.col3,
          min(x.frozen_start), min(x.total_start),
          coalesce(sum(case o2.locked when %s then o2.quantity else 0 end),0),
          coalesce(sum(o2.quantity),0)
        from (
          select oper.name as row1,  oper.location_id as row2,
               d.bucket as col1, d.startdate as col2, d.enddate as col3,
               coalesce(sum(case o1.locked when %s then o1.quantity else 0 end),0) as frozen_start,
               coalesce(sum(o1.quantity),0) as total_start
          from (%s) oper
          -- 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
          -- Planned and frozen quantity, based on start date
          left join out_operationplan o1
          on oper.name = o1.operation
          and d.startdate <= o1.startdate
          and d.enddate > o1.startdate
          -- Grouping
          group by oper.name, oper.location_id, d.bucket, d.startdate, d.enddate
        ) x
        -- Planned and frozen quantity, based on end date
        left join out_operationplan o2
        on x.row1 = o2.operation
        and x.col2 <= o2.enddate
        and x.col3 > o2.enddate
        -- Grouping and ordering
        group by x.row1, x.row2, x.col1, x.col2, x.col3
        order by %s, x.col2
      ''' % (sql_true(), sql_true(), basesql, request.report_bucket,
             request.report_startdate, request.report_enddate, sortsql)
        cursor.execute(query, baseparams)

        # Convert the SQl results to python
        for row in cursor.fetchall():
            yield {
                'operation': row[0],
                'location': row[1],
                'bucket': row[2],
                'startdate': python_date(row[3]),
                'enddate': python_date(row[4]),
                'locked_start': row[5],
                'total_start': row[6],
                'locked_end': row[7],
                'total_end': row[8],
            }
コード例 #30
0
class OverviewReport(GridPivot):
    '''
  A report showing the independent demand for each item.
  '''
    template = 'output/demand.html'
    title = _('Demand report')
    basequeryset = Item.objects.all()
    model = Item
    permissions = (("view_demand_report", "Can view demand report"), )
    rows = (GridFieldText('item',
                          title=_('item'),
                          key=True,
                          editable=False,
                          field_name='name',
                          formatter='detail',
                          extra='"role":"input/item"'), )
    crosses = (
        ('demand', {
            'title': _('demand')
        }),
        ('supply', {
            'title': _('supply')
        }),
        ('backlog', {
            'title': _('backlog')
        }),
    )
    help_url = 'user-guide/user-interface/plan-analysis/demand-report.html'

    @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, initially_hidden=True):
                reportclass.attr_sql += 'item.%s, ' % f.name.split('__')[-1]

    @classmethod
    def extra_context(reportclass, request, *args, **kwargs):
        if args and args[0]:
            request.session['lasttab'] = 'plan'
            return {
                'title':
                capfirst(force_text(Item._meta.verbose_name) + " " + args[0]),
                'post_title':
                ': ' + capfirst(force_text(_('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)
        cursor = connections[request.database].cursor()

        # Assure the item hierarchy is up to date
        Item.rebuildHierarchy(database=basequery.db)

        # Execute a query to get the backlog at the start of the horizon
        startbacklogdict = {}
        query = '''
      select items.name, coalesce(req.qty, 0) - coalesce(pln.qty, 0)
      from (%s) items
      left outer join (
        select parent.name, sum(quantity) qty
        from demand
        inner join item on demand.item_id = item.name
        inner join item parent on item.lft between parent.lft and parent.rght
        where status in ('open', 'quote')
        and due < %%s
        group by parent.name
        ) req
      on req.name = items.name
      left outer join (
        select parent.name, sum(operationplan.quantity) qty
        from operationplan
        inner join demand on operationplan.demand_id = demand.name        
          and operationplan.owner_id is null
          and operationplan.enddate < %%s
        inner join item on demand.item_id = item.name
        inner join item parent on item.lft between parent.lft and parent.rght
        group by parent.name
        ) pln
      on pln.name = items.name
      ''' % basesql
        cursor.execute(
            query,
            baseparams + (request.report_startdate, request.report_startdate))
        for row in cursor.fetchall():
            if row[0]:
                startbacklogdict[row[0]] = float(row[1])

        # Execute the query
        query = '''
        select y.name, %s
               y.bucket, y.startdate, y.enddate,
               min(y.orders),
               min(y.planned)
        from (
          select x.name as name, x.lft as lft, x.rght as rght,
               x.bucket as bucket, x.startdate as startdate, x.enddate as enddate,
               coalesce(sum(demand.quantity),0) as orders,
               min(x.planned) as planned
          from (
          select items.name as name, items.lft as lft, items.rght as rght,
                 d.bucket as bucket, d.startdate as startdate, d.enddate as enddate,
                 coalesce(sum(operationplan.quantity),0) as planned
          from (%s) items
          -- 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
          -- Include hierarchical children
          inner join item
          on item.lft between items.lft and items.rght
          -- Planned quantity
          left outer join operationplan
          on operationplan.type = 'DLVR'
          and operationplan.item_id = item.name
          and d.startdate <= operationplan.enddate
          and d.enddate > operationplan.enddate
          and operationplan.enddate >= %%s
          and operationplan.enddate < %%s
          -- Grouping
          group by items.name, items.lft, items.rght, d.bucket, d.startdate, d.enddate
        ) x
        -- Requested quantity
        inner join item
        on item.lft between x.lft and x.rght
        left join demand
        on item.name = demand.item_id
        and x.startdate <= demand.due
        and x.enddate > demand.due
        and demand.due >= %%s
        and demand.due < %%s
        and demand.status in ('open', 'quote')
        -- Grouping
        group by x.name, x.lft, x.rght, x.bucket, x.startdate, x.enddate
        ) y
        -- Ordering and grouping
        group by %s y.name, y.lft, y.rght, y.bucket, y.startdate, y.enddate
        order by %s, y.startdate
       ''' % (reportclass.attr_sql, basesql, reportclass.attr_sql, sortsql)
        cursor.execute(
            query,
            baseparams + (request.report_bucket, request.report_startdate,
                          request.report_enddate, request.report_startdate,
                          request.report_enddate, request.report_startdate,
                          request.report_enddate))

        # Build the python result
        previtem = None
        for row in cursor.fetchall():
            numfields = len(row)
            if row[0] != previtem:
                backlog = startbacklogdict.get(row[0], 0)
                previtem = row[0]
            backlog += float(row[numfields - 2]) - float(row[numfields - 1])
            res = {
                'item': row[0],
                'bucket': row[numfields - 5],
                'startdate': row[numfields - 4].date(),
                'enddate': row[numfields - 3].date(),
                'demand': round(row[numfields - 2], 1),
                'supply': round(row[numfields - 1], 1),
                'backlog': round(backlog, 1),
            }
            idx = 1
            for f in getAttributeFields(Item):
                res[f.field_name] = row[idx]
                idx += 1
            yield res