Beispiel #1
0
class Customer_admin(MultiDBModelAdmin):
    model = Customer
    raw_id_fields = ("owner",)
    save_on_top = True
    fieldsets = (
        (None, {"fields": ("name", "description", "owner")}),
        (
            _("advanced"),
            {
                "fields": ["category", "subcategory"]
                + [a[0] for a in getAttributes(Location) if a[3]],
                "classes": ("collapse",),
            },
        ),
    )
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_customer_change",
            "permissions": "input.change_customer",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_customer_comment",
        },
    ]
Beispiel #2
0
class Supplier_admin(MultiDBModelAdmin):
    model = Supplier
    raw_id_fields = ("available", "owner")
    save_on_top = True
    fieldsets = (
        (None, {"fields": ("name", "description")}),
        (
            _("advanced"),
            {
                "fields": ["category", "subcategory"]
                + [a[0] for a in getAttributes(Supplier) if a[3]],
                "classes": ("collapse",),
            },
        ),
    )
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_supplier_change",
            "permissions": "input.change_supplier",
        },
        {
            "name": "purchaseorders",
            "label": _("purchase orders"),
            "view": "input_purchaseorder_by_supplier",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_supplier_comment",
        },
    ]
Beispiel #3
0
 def loadItems(self):
   print('Importing items...')
   cnt = 0
   starttime = time()
   attrs = [ f[0] for f in getAttributes(Item) ]
   if attrs:
     attrsql = ', %s' % ', '.join(attrs)
   else:
     attrsql = ''
   self.cursor.execute('''
     SELECT
       name, description, operation_id, owner_id,
       price, category, subcategory, source %s
     FROM item %s
     ''' % (attrsql, self.filter_where))
   for i in self.cursor.fetchall():
     cnt += 1
     try:
       x = frepple.item(name=i[0], description=i[1], category=i[5], subcategory=i[6], source=i[7])
       if i[2]:
         x.operation = frepple.operation(name=i[2])
       if i[3]:
         x.owner = frepple.item(name=i[3])
       if i[4]:
         x.price = i[4]
       idx = 8
       for a in attrs:
         setattr(x, a, i[idx])
         idx += 1
     except Exception as e:
       print("Error:", e)
   print('Loaded %d items in %.2f seconds' % (cnt, time() - starttime))
Beispiel #4
0
class Calendar_admin(MultiDBModelAdmin):
    model = Calendar
    save_on_top = True
    inlines = [CalendarBucket_inline]
    fieldsets = (
        (None, {"fields": ("name", "defaultvalue")}),
        (
            _("advanced"),
            {
                "fields": ["description", "category", "subcategory"]
                + [a[0] for a in getAttributes(Calendar) if a[3]],
                "classes": ("collapse",),
            },
        ),
    )
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_calendar_change",
            "permissions": "input.change_calendar",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_calendar_comment",
        },
    ]
Beispiel #5
0
class ResourceSkill_admin(MultiDBModelAdmin):
    model = ResourceSkill
    raw_id_fields = ("resource", "skill")
    save_on_top = True
    fieldsets = (
        (None, {"fields": ("resource", "skill")}),
        (
            _("advanced"),
            {
                "fields": ["priority", "effective_start", "effective_end"]
                + [a[0] for a in getAttributes(ResourceSkill) if a[3]],
                "classes": ("collapse",),
            },
        ),
    )
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_resourceskill_change",
            "permissions": "input.change_resoureskill",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_resourceskill_comment",
        },
    ]
Beispiel #6
0
 def loadItems(self):
   print('Importing items...')
   cnt = 0
   starttime = time()
   attrs = [ f[0] for f in getAttributes(Item) ]
   if attrs:
     attrsql = ', %s' % ', '.join(attrs)
   else:
     attrsql = ''
   self.cursor.execute('''
     SELECT
       name, description, owner_id,
       price, category, subcategory, source %s
     FROM item %s
     ''' % (attrsql, self.filter_where))
   for i in self.cursor.fetchall():
     cnt += 1
     try:
       x = frepple.item(name=i[0], description=i[1], category=i[4], subcategory=i[5], source=i[6])
       if i[2]:
         x.owner = frepple.item(name=i[2])
       if i[3]:
         x.price = i[3]
       idx = 7
       for a in attrs:
         setattr(x, a, i[idx])
         idx += 1
     except Exception as e:
       print("Error:", e)
   print('Loaded %d items in %.2f seconds' % (cnt, time() - starttime))
Beispiel #7
0
class Demand_admin(MultiDBModelAdmin):
    model = Demand
    raw_id_fields = ("customer", "item", "operation", "owner")
    fieldsets = (
        (
            None,
            {
                "fields": (
                    "name",
                    "item",
                    "location",
                    "customer",
                    "due",
                    "quantity",
                    "priority",
                    "status",
                )
            },
        ),
        (
            _("advanced"),
            {
                "fields": [
                    "description",
                    "category",
                    "subcategory",
                    "batch",
                    "operation",
                    "minshipment",
                    "maxlateness",
                ]
                + [a[0] for a in getAttributes(Demand) if a[3]],
                "classes": ("collapse",),
            },
        ),
    )
    save_on_top = True
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_demand_change",
            "permissions": "input.change_demand",
        },
        {"name": "supplypath", "label": _("supply path"), "view": "supplypath_demand"},
        {
            "name": "constraint",
            "label": _("why short or late?"),
            "view": "output_constraint_demand",
        },
        {"name": "plan", "label": _("plan"), "view": "output_demand_pegging"},
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_demand_comment",
        },
    ]
Beispiel #8
0
class Item_admin(MultiDBModelAdmin):
    model = Item
    save_on_top = True
    raw_id_fields = ("owner", )
    search_fields = ("name", "description")
    fieldsets = (
        (None, {
            "fields": ("name", "description", "cost", "owner", "uom")
        }),
        (
            _("advanced"),
            {
                "fields":
                ["category", "subcategory", "type", "volume", "weight"] +
                [a[0] for a in getAttributes(Item) if a[3]],
                "classes": ("collapse", ),
            },
        ),
    )
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_item_change",
            "permissions": "input.change_item",
        },
        {
            "name": "supplypath",
            "label": _("supply path"),
            "view": "supplypath_item"
        },
        {
            "name": "whereused",
            "label": _("where used"),
            "view": "whereused_item"
        },
        {
            "name": "plan",
            "label": _("plan"),
            "view": "output_demand_plandetail"
        },
        {
            "name": "inventory",
            "label": _("inventory"),
            "view": "output_buffer_plandetail_by_item",
        },
        {
            "name": "inventorydetail",
            "label": _("inventory detail"),
            "view": "input_operationplanmaterial_plandetail_by_item",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_item_comment",
        },
    ]
Beispiel #9
0
class Location_admin(MultiDBModelAdmin):
    model = Location
    raw_id_fields = ("available", "owner")
    save_on_top = True
    fieldsets = (
        (None, {
            "fields": ("name", "owner")
        }),
        (
            _("Advanced"),
            {
                "fields":
                ["description", "category", "subcategory", "available"] +
                [a[0] for a in getAttributes(Location) if a[3]],
                "classes": ("collapse", ),
            },
        ),
    )
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_location_change",
            "permissions": "input.change_location",
        },
        {
            "name": "inboundorders",
            "label": _("inbound distribution"),
            "view": "input_distributionorder_in_by_location",
        },
        {
            "name": "outboundorders",
            "label": _("outbound distribution"),
            "view": "input_distributionorder_out_by_location",
        },
        {
            "name": "manufacturingorders",
            "label": _("manufacturing orders"),
            "view": "input_manufacturingorder_by_location",
        },
        {
            "name": "purchaseorders",
            "label": _("purchase orders"),
            "view": "input_purchaseorder_by_location",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_location_comment",
        },
    ]
Beispiel #10
0
class Buffer_admin(MultiDBModelAdmin):
    model = Buffer
    raw_id_fields = ("location", "item", "minimum_calendar")
    fieldsets = (
        (None, {"fields": ("item", "location", "onhand", "minimum")}),
        (
            _("advanced"),
            {
                "fields": [
                    "batch",
                    "description",
                    "category",
                    "subcategory",
                    "type",
                    "minimum_calendar",
                    "min_interval",
                ]
                + [a[0] for a in getAttributes(Buffer) if a[3]],
                "classes": ("collapse",),
            },
        ),
    )
    save_on_top = True
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "create_or_edit_buffer",
            "permissions": "input.change_buffer",
        },
        {"name": "supplypath", "label": _("supply path"), "view": "supplypath_buffer"},
        {"name": "whereused", "label": _("where used"), "view": "whereused_buffer"},
        {"name": "plan", "label": _("plan"), "view": "output_buffer_plandetail"},
        {
            "name": "plandetail",
            "label": _("plan detail"),
            "view": "input_operationplanmaterial_plandetail_by_buffer",
        },
        {
            "name": "constraint",
            "label": _("constrained demand"),
            "view": "output_constraint_buffer",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_buffer_comment",
        },
    ]
Beispiel #11
0
class PurchaseOrder_admin(MultiDBModelAdmin):
    model = PurchaseOrder
    raw_id_fields = ("item", "supplier")
    save_on_top = True
    fieldsets = (
        (
            None,
            {
                "fields": [
                    "reference",
                    "item",
                    "location",
                    "supplier",
                    "quantity",
                    "ordering_date",
                    "receipt_date",
                    "status",
                    "batch",
                ]
                + [a[0] for a in getAttributes(PurchaseOrder) if a[3]]
            },
        ),
    )
    exclude = (
        "type",
        "source",
        "criticality",
        "delay",
        "operation",
        "owner",
        "color",
        "origin",
        "destination",
        "demand",
        "name",
        "due",
        "startdate",
        "enddate",
    )
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_purchaseorder_change",
            "permissions": "input.change_purchaseorder",
        }
    ]
Beispiel #12
0
def getAttributeAPIFilterDefinition(cls):
    flt = {}
    for fld in getAttributes(cls):
        if fld[2] in (
                "number",
                "integer",
                "date",
                "datetime",
                "duration",
                "time",
        ):
            flt[fld[0]] = ["exact", "in", "gt", "gte", "lt", "lte"]
        elif fld[2] == "string":
            flt[fld[0]] = ["exact", "in", "contains"]
        elif fld[2] == "boolean":
            flt[fld[0]] = [
                "exact",
            ]
    return flt
Beispiel #13
0
class ItemDistribution_admin(MultiDBModelAdmin):
    model = ItemDistribution
    save_on_top = True
    raw_id_fields = ("item", "resource")
    fieldsets = (
        (None, {
            "fields": ("item", "location", "origin", "leadtime")
        }),
        (
            _("advanced"),
            {
                "fields": [
                    "sizeminimum",
                    "sizemultiple",
                    "sizemaximum",
                    "batchwindow",
                    "cost",
                    "priority",
                    "fence",
                    "effective_start",
                    "effective_end",
                    "resource",
                    "resource_qty",
                ] + [a[0] for a in getAttributes(ItemDistribution) if a[3]],
                "classes": ("collapse", ),
            },
        ),
    )
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_itemdistribution_change",
            "permissions": "input.change_itemdistribution",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_itemdistribution_comment",
        },
    ]
Beispiel #14
0
class OperationResource_admin(MultiDBModelAdmin):
    model = OperationResource
    raw_id_fields = ("operation", "resource", "skill")
    save_on_top = True
    exclude = ("id", )
    fieldsets = (
        (None, {
            "fields": ("operation", "resource", "quantity")
        }),
        (
            _("Advanced"),
            {
                "fields": [
                    "skill",
                    "setup",
                    "quantity_fixed",
                    "effective_start",
                    "effective_end",
                    "name",
                    "priority",
                    "search",
                ] + [a[0] for a in getAttributes(OperationResource) if a[3]],
                "classes": ("collapse", ),
            },
        ),
    )
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_operationresource_change",
            "permissions": "input.change_operationresource",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_operationresource_comment",
        },
    ]
Beispiel #15
0
class OperationMaterial_admin(MultiDBModelAdmin):
    model = OperationMaterial
    raw_id_fields = ("operation", "item")
    save_on_top = True
    exclude = ("id", )
    fieldsets = (
        (None, {
            "fields": ("operation", "item", "type", "quantity")
        }),
        (
            _("advanced"),
            {
                "fields": [
                    "quantity_fixed",
                    "transferbatch",
                    "offset",
                    "effective_start",
                    "effective_end",
                    "name",
                    "priority",
                    "search",
                ] + [a[0] for a in getAttributes(OperationMaterial) if a[3]],
                "classes": ("collapse", ),
            },
        ),
    )
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_operationmaterial_change",
            "permissions": "input.change_operationmaterial",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_operationmaterial_comment",
        },
    ]
Beispiel #16
0
  def run(cls, database=DEFAULT_DB_ALIAS, **kwargs):
    import frepple

    if cls.filter:
      filter_and = "and %s " % cls.filter
      filter_where = "where %s " % cls.filter
    else:
      filter_and = ""
      filter_where = ""

    with connections[database].chunked_cursor() as cursor:
      cnt = 0
      starttime = time()
      attrs = [ f[0] for f in getAttributes(Item) ]
      if attrs:
        attrsql = ', %s' % ', '.join(attrs)
      else:
        attrsql = ''
      cursor.execute('''
        SELECT
          name, description, owner_id,
          cost, category, subcategory, source %s
        FROM item %s
        ''' % (attrsql, filter_where))
      for i in cursor:
        cnt += 1
        try:
          x = frepple.item(name=i[0], description=i[1], category=i[4], subcategory=i[5], source=i[6])
          if i[2]:
            x.owner = frepple.item(name=i[2])
          if i[3]:
            x.cost = i[3]
          idx = 7
          for a in attrs:
            setattr(x, a, i[idx])
            idx += 1
        except Exception as e:
          logger.error("**** %s ****" % e)
      logger.info('Loaded %d items in %.2f seconds' % (cnt, time() - starttime))
Beispiel #17
0
def getAttributeAPIFields(cls):
    return tuple(i[0] for i in getAttributes(cls))
Beispiel #18
0
    def run(cls, cluster=-1, database=DEFAULT_DB_ALIAS, **kwargs):
        cls.attrs = [
            x for x in getAttributes(OperationPlan) if x[0] != "forecast"
        ]

        # Export operationplans to a temporary table
        cursor = connections[database].cursor()
        sql = """
            create temporary table tmp_operationplan (
                name character varying(1000),
                type character varying(5) NOT NULL,
                status character varying(20),
                quantity numeric(20,8) NOT NULL,
                startdate timestamp with time zone,
                enddate timestamp with time zone,
                criticality numeric(20,8),
                delay numeric,
                plan jsonb,
                source character varying(300),
                lastmodified timestamp with time zone NOT NULL,
                operation_id character varying(300),
                owner_id character varying(300),
                item_id character varying(300),
                destination_id character varying(300),
                origin_id character varying(300),
                location_id character varying(300),
                supplier_id character varying(300),
                demand_id character varying(300),
                due timestamp with time zone,
                color numeric(20,8),
                reference character varying(300) NOT NULL,
                batch character varying(300),
                quantity_completed numeric(20,8)
            """
        for attr in cls.attrs:
            if attr[2] == "boolean":
                sql += ", %s boolean" % attr[0]
            elif attr[2] == "duration":
                sql += ", %s interval" % attr[0]
            elif attr[2] == "integer":
                sql += ", %s integer" % attr[0]
            elif attr[2] == "number":
                sql += ", %s numeric(15,6)" % attr[0]
            elif attr[2] == "string":
                sql += ", %s character varying(300)" % attr[0]
            elif attr[2] == "time":
                sql += ", %s time without time zone" % attr[0]
            elif attr[2] == "date":
                sql += ", %s date" % attr[0]
            elif attr[2] == "datetime":
                sql += ", %s timestamp with time zone" % attr[0]
            else:
                raise Exception("Unknown attribute type %s" % attr[2])
        sql += ")"
        cursor.execute(sql)

        cursor.copy_from(
            CopyFromGenerator(
                cls.getData(
                    cls.parent.timestamp,
                    cluster=cluster,
                    accepted_status=[
                        "confirmed", "approved", "completed", "closed"
                    ],
                )),
            table="tmp_operationplan",
            size=1024,
            sep="\v",
        )

        forecastfield0 = ""
        forecastfield1 = ""

        # Merge temp table into the actual table
        sql = ("""
            update operationplan
                set name=tmp.name, type=tmp.type, status=tmp.status,
                quantity=tmp.quantity, startdate=tmp.startdate, enddate=tmp.enddate,
                criticality=tmp.criticality, delay=tmp.delay * interval '1 second',
                plan=tmp.plan, source=tmp.source,
                lastmodified=tmp.lastmodified, operation_id=tmp.operation_id, owner_id=tmp.owner_id,
                item_id=tmp.item_id, destination_id=tmp.destination_id, origin_id=tmp.origin_id,
                location_id=tmp.location_id, supplier_id=tmp.supplier_id, demand_id=tmp.demand_id,
                due=tmp.due,%s color=tmp.color, batch=tmp.batch, quantity_completed=tmp.quantity_completed
            """ % forecastfield0)
        for a in cls.attrs:
            sql += ", %s=tmp.%s" % (a[0], a[0])
        sql += """
            from tmp_operationplan as tmp
            where operationplan.reference = tmp.reference
            """
        cursor.execute(sql)

        # Make sure any deleted confirmed MO from Plan Editor gets deleted in the database
        # Only MO can currently be deleted through Plan Editor
        cursor.execute("""
            delete from operationplan
            where status in ('confirmed','approved','completed','closed')
            and type = 'MO'
            and not exists (select 1 from tmp_operationplan where reference = operationplan.reference)
            """)

        cursor.execute("""
            insert into operationplan
              (name,type,status,quantity,startdate,enddate,
              criticality,delay,plan,source,lastmodified,
              operation_id,owner_id,
              item_id,destination_id,origin_id,
              location_id,supplier_id,
              demand_id,due,color,reference,batch,quantity_completed%s)
            select name,type,status,quantity,startdate,enddate,
              criticality,delay * interval '1 second',plan,source,lastmodified,
              operation_id,owner_id,
              item_id,destination_id,origin_id,
              location_id,supplier_id,
              demand_id,due,color,reference,batch,quantity_completed%s
            from tmp_operationplan
            where not exists (
              select 1
              from operationplan
              where operationplan.reference = tmp_operationplan.reference
              );
            """ % (forecastfield1, forecastfield1))

        # directly injecting proposed records in operationplan table
        cursor.copy_from(
            CopyFromGenerator(
                cls.getData(
                    cls.parent.timestamp,
                    cluster=cluster,
                    accepted_status=["proposed"],
                )),
            table="operationplan",
            size=1024,
            sep="\v",
            columns=[
                "name",
                "type",
                "status",
                "quantity",
                "startdate",
                "enddate",
                "criticality",
                "delay",
                "plan",
                "source",
                "lastmodified",
                "operation_id",
                "owner_id",
                "item_id",
                "destination_id",
                "origin_id",
                "location_id",
                "supplier_id",
                "demand_id",
                "due",
                "color",
                "reference",
                "batch",
                "quantity_completed",
            ] + [a[0] for a in cls.attrs],
        )

        # update demand table specific fields
        cursor.execute("""
            with cte as (
              select demand_id, sum(quantity) plannedquantity, max(enddate) deliverydate, max(enddate)-due as delay
              from operationplan
              where demand_id is not null and owner_id is null
              group by demand_id, due
            )
            update demand
              set delay = cte.delay,
              plannedquantity = cte.plannedquantity,
              deliverydate = cte.deliverydate
            from cte
            where cte.demand_id = demand.name
            """)
        cursor.execute("""
            update demand set
              delay = null,
              plannedquantity = null,
              deliverydate = null
            where (delay is not null or plannedquantity is not null or deliverydate is not null)
            and not exists(
              select 1 from operationplan where owner_id is null and operationplan.demand_id = demand.name
              )
            """)
        cursor.execute("""
            update demand
              set plannedquantity = 0
            where status in ('open','quote') and plannedquantity is null
            """)
Beispiel #19
0
class Operation_admin(MultiDBModelAdmin):
    model = Operation
    raw_id_fields = ("item", "available", "owner")
    save_on_top = True
    fieldsets = (
        (
            None,
            {
                "fields": (
                    "name",
                    "type",
                    "item",
                    "location",
                    "duration",
                    "duration_per",
                    "owner",
                )
            },
        ),
        (
            _("advanced"),
            {
                "fields": [
                    "description",
                    "category",
                    "subcategory",
                    "fence",
                    "posttime",
                    "sizeminimum",
                    "sizemultiple",
                    "sizemaximum",
                    "cost",
                    "available",
                    "priority",
                    "search",
                    "effective_start",
                    "effective_end",
                ]
                + [a[0] for a in getAttributes(Operation) if a[3]],
                "classes": ("collapse",),
            },
        ),
    )
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_operation_change",
            "permissions": "input.change_operation",
        },
        {
            "name": "supplypath",
            "label": _("supply path"),
            "view": "supplypath_operation",
        },
        {"name": "whereused", "label": _("where used"), "view": "whereused_operation"},
        {"name": "plan", "label": _("plan"), "view": "output_operation_plandetail"},
        {
            "name": "plandetail",
            "label": _("manufacturing orders"),
            "view": "input_manufacturingorder_by_operation",
        },
        {
            "name": "constraint",
            "label": _("constrained demand"),
            "view": "output_constraint_operation",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_operation_comment",
        },
    ]
Beispiel #20
0
def getAttributeAPIReadOnlyFields(cls):
    return tuple(i[0] for i in getAttributes(cls) if not i[3])
Beispiel #21
0
class Resource_admin(MultiDBModelAdmin):
    model = Resource
    raw_id_fields = (
        "maximum_calendar",
        "location",
        "setupmatrix",
        "owner",
        "available",
        "efficiency_calendar",
    )
    fieldsets = (
        (None, {"fields": ("name", "location", "type", "maximum")}),
        (
            _("advanced"),
            {
                "fields": [
                    "description",
                    "category",
                    "subcategory",
                    "constrained",
                    "owner",
                    "maximum_calendar",
                    "available",
                    "cost",
                    "maxearly",
                    "setupmatrix",
                    "efficiency",
                    "efficiency_calendar",
                ]
                + [a[0] for a in getAttributes(Resource) if a[3]],
                "classes": ("collapse",),
            },
        ),
    )
    save_on_top = True
    tabs = [
        {
            "name": "edit",
            "label": _("edit"),
            "view": "admin:input_resource_change",
            "permissions": "input.change_resource",
        },
        {
            "name": "supplypath",
            "label": _("supply path"),
            "view": "supplypath_resource",
        },
        {"name": "whereused", "label": _("where used"), "view": "whereused_resource"},
        {"name": "plan", "label": _("plan"), "view": "output_resource_plandetail"},
        {
            "name": "plandetail",
            "label": _("plan detail"),
            "view": "input_operationplanresource_plandetail",
        },
        {
            "name": "constraint",
            "label": _("constrained demand"),
            "view": "output_constraint_resource",
        },
        {
            "name": "messages",
            "label": _("messages"),
            "view": "admin:input_resource_comment",
        },
    ]