Cruddata Approval

Introduction #

SmartChart CRUD supports complete workflow approval capabilities, including approval flow definitions (multi-node process configuration) and data change approval (insert/update/delete requires approval before taking effect). Approval flows are implemented through three system tables (flowinfo, flowinstances, flowtasks), while data approval uses the modify_request table to record changes.

Approval Type Description
Approval Flow Multi-node process definition for work orders, contracts, etc.
Data Change Approval Insert/update data enters approval queue, takes effect only after approval

Approval Flow #

MySQL Table Creation #

drop table if exists oa_flowinfo;
CREATE TABLE oa_flowinfo(
    id int PRIMARY KEY auto_increment,
    tid smallint default 0 comment 'Tenant ID',
    uuid varchar(20),
    name varchar(50),
    description varchar(200),
    category varchar(50),
    flow TEXT,
    status varchar(20),
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    updater varchar(50),
    UNIQUE uc(tid,name)
) comment 'Approval Flow Definition';

drop table if exists oa_flowinstances;
CREATE TABLE oa_flowinstances(
    id int PRIMARY KEY auto_increment,
    tid smallint default 0 comment 'Tenant ID',
    uuid varchar(50),
    title varchar(100),
    remark varchar(500),
    formId varchar(50),
    variables varchar(500),
    definitionId varchar(50),
    applicant varchar(50),
    status varchar(50),
    currentNodeId varchar(50),
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    updater varchar(50)
) comment 'Approval Instance';

drop table if exists oa_flowtasks;
CREATE TABLE oa_flowtasks(
    id int PRIMARY KEY auto_increment,
    tid smallint default 0 comment 'Tenant ID',
    uuid varchar(50),
    instanceId varchar(50),
    nodeId varchar(50),
    nodeName varchar(50),
    assignee varchar(50),
    status varchar(50),
    instructions varchar(200),
    variables varchar(500),
    comment varchar(100),
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    updater varchar(50)
) comment 'Approval Task';

SQLite Table Creation #

DROP TABLE IF EXISTS oa_flowinfo;
CREATE TABLE oa_flowinfo(
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    tid INTEGER DEFAULT 0,
    uuid TEXT, name TEXT, description TEXT, category TEXT,
    flow TEXT, status TEXT,
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    updater TEXT,
    UNIQUE(tid, name)
);
-- Similar for oa_flowinstances and oa_flowtasks

Import Approval Flow Page #

Available in Professional edition — contact support.

Data Change Approval #

  • Configuration method is the same for insert, update, approval, and import datasets — see Data Update
  • Create datasets and specify the corresponding dataset IDs to enable
  • For approval DS, create the approval table first, then define the write configuration:
create table modify_request(
    id INT NOT NULL AUTO_INCREMENT,
    tablename VARCHAR(50) NOT NULL,
    codename VARCHAR(50) NOT NULL,
    code VARCHAR(50) NOT NULL,
    columnname varchar(50),
    oldvalue varchar(100),
    newvalue varchar(255),
    requester varchar(50),
    checker varchar(50),
    flag int default 0,
    request_remark varchar(200),
    check_remark varchar(200),
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
) comment 'Change Log';
dataset={
    "table": "modify_request",
    "sFields": [],
    "id": "id",
    "fDict": {},
    "autoDict": {"tablename": "table_name", "codename": "pk_name", "requester": "$username"}
}
  • Two approval modes: open a separate window to select fields for modification (enable approval), or edits don’t take effect and flow to approval (enable approval editing)

  • The approval interface is also generated via CRUD, using two action buttons:

import json
action = '$action'
updatelist = "$updatelist"
sql = ''
if action == 'check':
    contents = ds_sql('datasource', f'select tablename,columnname,newvalue,codename,code from modify_request where id in ({updatelist})')
    sql = []
    for content in contents[1:]:
        if content[1]:
            sql.append(f"update {content[0]} set {content[1]}='{content[2]}' where {content[3]}='{content[4]}'")
        else:
            changeList = []
            changeDict = json.loads(content[2])
            for k, v in changeDict.items():
                changeList.append(f"{k}='{v}'")
            changeList = ','.join(changeList)
            if changeList:
                sql.append(f"update {content[0]} set {changeList} where {content[3]}='{content[4]}'")
    sql.append(f"update modify_request set flag=2, checker='$username' where id in ({updatelist})")
    sql = ';'.join(sql)
elif action == 'reject':
    sql = f"update modify_request set flag=1, checker='$username' where id in ({updatelist})"
if sql:
    ds = ds_sql('datasource', sql)