Skip to content

Reconsider Child Tables

Reconsider Child Tables

  • Child Table seems logical for most line items where further processing of row item in child table is limited.
  • Consider using a different parent doctype altogether if you need the row item in child table to have own stages and processes.
  • In case of API linking. Add a link field to "Parent" doctype on the new created Doctype that acts as line item to "Parent". Both are Parent level doctypes.

HTML Field based customization

Set Options for HTML field in DocType JS
frm.set_df_property(
  'process_details_html',
  'options',
  frappe.render_template('process_checklist_table', {
    doc: fetchValues(frm).process_details,
    id:
      frm.doc.__islocal === 1
        ? ''
        : frm.doc.name + '-process-details',
    docstatus: frm.doc.docstatus,
  }),
);

Template public/js/templates/process_checklist_table.html

HTML Template
<style>
    .table-container {
        overflow: auto; /* Enable scrolling */
        background-color: #ffffff;
    }
    .frappe-control .address-box {
        background-color: #ffffff;
    }

    /* Apply styles to the table header */
    .table-container table thead {
        position: sticky;
        top: -20px;
        background-color: white;
        z-index: 1;
    }
</style>
<div class="table-container">
    <div class="address-box" style="max-height: 35rem;">
        <table class="table table-bordered border-4" style="text-align: center;">
            <thead>
                <tr>
                    {% if id && docstatus==0%}
                    <th><input type="checkbox" class="{{id}}-select-all"></th>
                    <th>{{ frappe.utils.icon("project-2", "sm") }}</th>
                    {% endif %}
                    <th>No.</th>
                    <th>Document Code</th>
                    <th>Description</th>
                    {% if id%}
                    <th>Standard Template</th>
                    {% endif %}
                    <th>File name</th>
                    <th>Client Upload</th>
                    <th>Server Upload</th>
                    <th>Public</th>
                    <th style="min-width: 7rem;">Upload Date</th>
                    <th style="min-width: 13rem">Comments / Justification</th>
                    <th>Track Exception</th>
                    <th style="min-width: 7rem;">Due Date</th>
                    <th>Retain/Waive</th>
                    <th>Approval Required</th>
                    <th>Send Email</th>
                    {% if id && docstatus==0%}
                    <th>{{ frappe.utils.icon("setting-gear", "sm") }}</th>
                    {% endif %}
                </tr>
            </thead>
            <tbody>
                {% for (let i=0; i<doc.length; i++ ){ %} <tr>

                    {% if id && docstatus==0%}
                    <!-- Select Row -->
                    <td style="vertical-align: initial;">
                        {% if doc[i].track_exception != "Yes"%}
                        <input type="checkbox" class="{{id}}-select-row">
                        {% else %}
                        <input type="checkbox" class="{{id}}-select-row" hidden>
                        {% endif %}
                    </td>


                    <!-- Attachments -->
                    <td style="vertical-align: initial;">
                        <input type="file" hidden class="{{id}}-attach-input" />
                        {% if doc[i].track_exception != "Yes"%}
                        <a class="{{id}}-attach-file">{{ frappe.utils.icon("attachment", "sm") }}</a>
                        {% else %}
                        <a class="{{id}}-attach-file" hidden>{{ frappe.utils.icon("attachment", "sm") }}</a>
                        {% endif %}
                    </td>
                    {% endif %}

                    <!-- No. -->
                    <td>{{ i+1 }}</td>

                    <!-- Document Code -->
                    <td>
                        <span
                            style="display: inline-block; width: 6rem; white-space: nowrap; overflow: hidden !important; text-overflow: ellipsis;">
                            {%=doc[i].document_code%}
                        </span>
                    </td>

                    <!-- Description -->
                    <td>
                        <span
                            style="display: inline-block; width: 10rem; white-space: nowrap; overflow: hidden !important; text-overflow: ellipsis;">
                            {%=doc[i].description%}
                        </span>
                    </td>

                    <!-- Standard Template -->
                    {% if id%}
                    <td style="vertical-align: middle;">
                        {% if doc[i].standard_template_s3_key%}
                        <a class="{{id}}-standard-template-download">
                            <span
                                style="width: 8rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: inline-block;">
                                {%=doc[i].standard_template_name%}
                            </span>
                        </a>
                        {% else %}
                        <a class="{{id}}-standard-template-download" hidden>
                        </a>
                        {% endif %}
                    </td>
                    {% endif %}

                    <!-- File Name -->
                    <td style="vertical-align: middle;">

                        {% if doc[i].file%}
                        <a>
                            <span class=" {{id}}-preview-file"
                                style="display: inline-block; width: 8rem; white-space: nowrap; overflow: hidden !important; text-overflow: ellipsis;">
                                {%=doc[i].file_name%}
                            </span>
                        </a>
                        <br>
                        <a class="{{id}}-remove-file">
                            <span>
                                {{ frappe.utils.icon("close", "sm") }}
                            </span>
                        </a>
                        <a class="{{id}}-s3-download" hidden>
                            <span
                                style="width: 8rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: inline-block;">
                                {%=doc[i].file_name%}
                            </span>
                        </a>
                        {% else %}

                        <a hidden>
                            <span class=" {{id}}-preview-file"
                                style="display: inline-block; width: 8rem; white-space: nowrap; overflow: hidden !important; text-overflow: ellipsis;">
                                {%=doc[i].file_name%}
                            </span>
                        </a>
                        <a class="{{id}}-remove-file" hidden>
                            <span>
                                {{ frappe.utils.icon("close", "sm") }}
                            </span>
                        </a>

                        <a class="{{id}}-s3-download">
                            <span
                                style="width: 8rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: inline-block;">
                                {%=doc[i].file_name%}
                            </span>
                        </a>

                        {% endif %}
                    </td>

                    <!-- Client Upload -->
                    <td>{%=doc[i].client_upload_yes_no%}</td>

                    <!-- Server Upload -->
                    <td>{%=doc[i].server_upload_yes_no%}</td>

                    <!-- Public -->
                    <td>{%=doc[i].public%}</td>

                    <!-- Upload Date -->
                    <td>{%=doc[i].upload_date%}</td>

                    <!-- Comments / Justification -->
                    <td>{%=doc[i].comments%}</td>

                    <!-- Track Exception -->
                    <td>{%=doc[i].track_exception%}</td>

                    <!-- Due Date -->
                    <td>{%=doc[i].due_date%}</td>

                    <!-- Retain/Waive -->
                    <td>{%=doc[i].retain_waive%}</td>

                    <!-- Approval Required -->
                    <td>{%=doc[i].approval_required%}</td>

                    <!-- Send Email -->
                    <td>{%=doc[i].send_email%}</td>

                    <!-- Edit -->
                    {% if id && docstatus==0%}
                    <td style="vertical-align: middle;">
                        {% if doc[i].track_exception != "Yes"%}
                        <a class="{{id}}-edit-row">{{ frappe.utils.icon("edit", "sm") }}</a>
                        {% else %}
                        <a class="{{id}}-edit-row" hidden>{{ frappe.utils.icon("edit", "sm") }}</a>
                        {% endif %}
                    </td>
                    {% endif %}

                    </tr>
                    {% }%}
            </tbody>
        </table>
    </div>
</div>

{% if id %}
<div class="position-relative h-100">
    <div style="top: 0; left: 0; margin-bottom: 5px">
        {% if docstatus==0%}
        <button class="btn btn-xs btn-default {{id}}-add-row">
            Add
        </button>&nbsp;&nbsp;
        <button class="btn btn-xs btn-default {{id}}-remove-row">
            Remove
        </button>&nbsp;&nbsp;

        <button class="btn btn-xs btn-default {{id}}-upload-all">
            Upload
        </button>
        {% else %}
        &nbsp;&nbsp;
        {% endif %}
    </div>

    <div class="position-absolute" style="top: 0; right: 0;">
        <button class="btn btn-xs btn-default {{id}}-email">
            {{ frappe.utils.icon("mail", "sm") }}
        </button>
    </div>
</div>
{% endif %}

JS Button Actions

Set button actions and create Frappe Dialog
function addNewRowEvents(frm) {
  $('.' + frm.doc.name + '-common_documents-add-row').unbind();
  $('.' + frm.doc.name + '-common_documents-add-row').on('click', function () {
    const assetName = 'common_documents';
    rowDialog(frm, {}, assetName);
  });
}

function rowDialog(frm, defaultValues = {}, assetName, index = null) {
  const d = new frappe.ui.Dialog({
    title: index !== null ? 'Edit' : 'Add',
    fields: getFields(defaultValues, index === null),
    primary_action_label: 'Confirm',
    primary_action: values => {
        // do something with values
    },
    secondary_action_label: 'Cancel',
    secondary_action: () => {
      d.hide();
    },
  });
  d.show();
  d.fields_dict.document_code.get_query = function () {
    return {
      filters: [
          ['Document Code', 'process_execution_checklist', '=', 1],
          ['Document Code', 'product', '=', frm.doc.product_name],
      ],
    }
  };
}