335 lines
8.7 KiB
TypeScript
335 lines
8.7 KiB
TypeScript
import {
|
|
IAction,
|
|
IActionResult,
|
|
IActionNode,
|
|
IActionProperty,
|
|
IContext,
|
|
} from "../types/ActionTypes";
|
|
import { actionAddins } from ".";
|
|
import { KintoneRestAPIClient } from "@kintone/rest-api-client";
|
|
import { Lookup } from "@kintone/rest-api-client/lib/src/KintoneFields/types/property";
|
|
import { FieldForm, FieldType } from "../types/FieldLayout";
|
|
interface Props {
|
|
displayName: string;
|
|
sources: Sources;
|
|
dataMapping: DataMapping;
|
|
}
|
|
|
|
interface DataMapping {
|
|
data: Mapping[];
|
|
createWithNull: boolean;
|
|
}
|
|
|
|
interface Mapping {
|
|
id: string;
|
|
from: From;
|
|
to: To;
|
|
isKey: boolean;
|
|
}
|
|
|
|
|
|
|
|
interface To {
|
|
app: App;
|
|
fields:FieldForm[];
|
|
isDialogVisible: boolean;
|
|
}
|
|
|
|
|
|
interface From {
|
|
sharedText: string;
|
|
id: string;
|
|
objectType: 'variable'|'field'|'text';
|
|
}
|
|
|
|
interface IVar extends From{
|
|
name:{
|
|
name:string;
|
|
}
|
|
}
|
|
|
|
interface IFromField extends From,FieldForm{
|
|
|
|
}
|
|
interface Sources {
|
|
app: App;
|
|
}
|
|
|
|
interface App {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
createdate: string;
|
|
}
|
|
|
|
export class DataUpdateAction implements IAction {
|
|
name: string;
|
|
actionProps: IActionProperty[];
|
|
dataMappingProps: Props;
|
|
constructor() {
|
|
this.name = "データ更新";
|
|
this.actionProps = [];
|
|
this.dataMappingProps = {} as Props;
|
|
this.register();
|
|
}
|
|
|
|
async process(
|
|
prop: IActionNode,
|
|
event: any,
|
|
context: IContext
|
|
): Promise<IActionResult> {
|
|
this.actionProps = prop.actionProps;
|
|
this.dataMappingProps = prop.ActionValue as Props;
|
|
console.log(context);
|
|
let result = {
|
|
canNext: true,
|
|
result: "",
|
|
} as IActionResult;
|
|
try {
|
|
const lookupFixedFieldCodes = await getLookupFixedFieldCodes(
|
|
this.dataMappingProps.sources.app.id
|
|
);
|
|
|
|
// createWithNull が有効な場合は、4 番目のパラメーターを true にして doUpdate 関数ブランチを実行します。
|
|
if (this.dataMappingProps.dataMapping.createWithNull) {
|
|
await doUpdate(
|
|
this.dataMappingProps.dataMapping.data,
|
|
this.dataMappingProps.sources.app.id,
|
|
context,
|
|
true, // キーがない場合、またはキーでターゲットが見つからない場合に、マッピング条件によって新しいレコードを作成するかどうかを決定するために使用されます。
|
|
lookupFixedFieldCodes
|
|
);
|
|
} else if (
|
|
// キーがないと更新対象を取得できないため、この時点でのみ更新が行われます。 doUpdate 関数の 4 番目のパラメーターは false です。
|
|
this.dataMappingProps.dataMapping.data
|
|
.map((m) => m.isKey)
|
|
.find((isKey) => isKey === true)
|
|
) {
|
|
await doUpdate(
|
|
this.dataMappingProps.dataMapping.data,
|
|
this.dataMappingProps.sources.app.id,
|
|
context,
|
|
false,
|
|
lookupFixedFieldCodes
|
|
);
|
|
} else {
|
|
await doCreate(
|
|
this.dataMappingProps.dataMapping.data,
|
|
this.dataMappingProps.sources.app.id,
|
|
context,
|
|
lookupFixedFieldCodes
|
|
);
|
|
}
|
|
} catch (error) {
|
|
console.error("DataMappingAction error", error);
|
|
result.canNext = false;
|
|
}
|
|
console.log("dataMappingProps", this.dataMappingProps);
|
|
|
|
return result;
|
|
}
|
|
|
|
register(): void {
|
|
actionAddins[this.name] = this;
|
|
}
|
|
}
|
|
|
|
new DataUpdateAction();
|
|
|
|
const getContextVarByPath = (obj: any, path: string) => {
|
|
return path.split(".").reduce((o, k) => (o || {})[k], obj);
|
|
};
|
|
|
|
interface UpdateRecord {
|
|
id: string;
|
|
record: {
|
|
[key: string]: {
|
|
value: any;
|
|
};
|
|
};
|
|
}
|
|
|
|
const client = new KintoneRestAPIClient();
|
|
|
|
const getFromValue=(item:Mapping,context:IContext)=>{
|
|
if (item.from.objectType === "variable") {
|
|
const rfrom =item.from as IVar;
|
|
return getContextVarByPath(context.variables,rfrom.name.name);
|
|
}else if(item.from.objectType === "field"){
|
|
const field = item.from as IFromField;
|
|
return context.record[field.code].value;
|
|
}
|
|
else {
|
|
return item.from.sharedText;
|
|
}
|
|
}
|
|
|
|
const doUpdate = async (
|
|
mappingData: Mapping[],
|
|
appId: string,
|
|
context: IContext,
|
|
needCreate: boolean,
|
|
lookupFixedFieldCodes: string[]
|
|
) => {
|
|
const targetField = await findUpdateField(mappingData, appId, context);
|
|
console.log(targetField);
|
|
if (targetField.records.length === 0 && needCreate) {
|
|
await doCreate(mappingData, appId, context, lookupFixedFieldCodes);
|
|
} else {
|
|
// マッピングデータを単純なオブジェクトに処理し、ソース値が変数の場合は変数を置き換えます。
|
|
const mappingRules = mappingData
|
|
.filter(
|
|
(m) =>
|
|
Object.keys(m.from).length > 0 &&
|
|
!lookupFixedFieldCodes.includes(m.to.fields[0].code)
|
|
)
|
|
.map((m) => {
|
|
if (m.from.objectType === "variable") {
|
|
const rfrom =m.from as IVar;
|
|
return {
|
|
value: getContextVarByPath(context.variables,rfrom.name.name),
|
|
code: m.to.fields[0].code,
|
|
};
|
|
}else if(m.from.objectType === "field"){
|
|
const field = m.from as IFromField;
|
|
return {
|
|
value: context.record[field.code].value,
|
|
code: m.to.fields[0].code,
|
|
}
|
|
}
|
|
else {
|
|
return {
|
|
value: m.from.sharedText,
|
|
code: m.to.fields[0].code,
|
|
};
|
|
}
|
|
});
|
|
|
|
const updateRecords: UpdateRecord[] = targetField.records.map(
|
|
(targetRecord) => {
|
|
const updateRecord: UpdateRecord["record"] = {};
|
|
|
|
// マッピング内のルールにヒットしたフィールドのみが更新されます。
|
|
for (const mapping of mappingRules) {
|
|
if (targetRecord[mapping.code]) {
|
|
updateRecord[mapping.code] = {
|
|
value: mapping.value,
|
|
};
|
|
}
|
|
}
|
|
|
|
return {
|
|
id: targetRecord.$id.value as string,
|
|
record: updateRecord,
|
|
};
|
|
}
|
|
);
|
|
|
|
console.log(updateRecords);
|
|
await client.record.updateRecords({
|
|
app: appId,
|
|
records: updateRecords,
|
|
});
|
|
}
|
|
};
|
|
|
|
const makeQuery=(field:FieldForm,key:any)=>{
|
|
if(field.type===FieldType.NUMBER || field.type===FieldType.RECORD_NUMBER){
|
|
return `${field.code} = ${Number(key)}`
|
|
}
|
|
if(typeof key==='string'){
|
|
return `${field.code} = "${key}"`
|
|
}
|
|
}
|
|
|
|
|
|
const findUpdateField = async (
|
|
mappingData: Mapping[],
|
|
appId: string,
|
|
context: IContext
|
|
) => {
|
|
const queryStr = mappingData
|
|
.filter((m) => m.to.app && m.to.fields && m.to.fields.length > 0 && m.isKey)
|
|
.map((m) => {
|
|
if (m.from.objectType === "variable") {
|
|
const vfrom = m.from as IVar;
|
|
return makeQuery(m.to.fields[0],getContextVarByPath(context.variables , vfrom.name.name));
|
|
}
|
|
else if(m.from.objectType === "field"){
|
|
const field = m.from as IFromField;
|
|
return makeQuery(m.to.fields[0],context.record[field.code].value);
|
|
}
|
|
else{
|
|
return makeQuery(m.to.fields[0],m.from.sharedText);
|
|
}
|
|
})
|
|
.join("&");
|
|
// 検索条件が空の場合は全レコードを返すため、検索対象が見つからない場合は検索は行われません。
|
|
if (queryStr.length === 0) {
|
|
return {
|
|
records: [],
|
|
};
|
|
} else {
|
|
return await client.record.getRecords({
|
|
app: appId,
|
|
// query: undefined
|
|
query: queryStr,
|
|
});
|
|
}
|
|
};
|
|
|
|
const doCreate = async (
|
|
mappingData: Mapping[],
|
|
appId: string,
|
|
context: IContext,
|
|
lookupFixedFieldCodes: string[]
|
|
) => {
|
|
const filterHandler = (item:Mapping)=>{
|
|
if(!item.to.fields || item.to.fields.length===0){
|
|
return false;
|
|
}
|
|
if(item.from.objectType === "variable" && (item.from as IVar).name.name ){
|
|
return true;
|
|
}
|
|
if(item.from.objectType === "field" && (item.from as IFromField).code){
|
|
return true;
|
|
}
|
|
if(item.from.objectType === "text" && item.from.sharedText!==null){
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
const record = mappingData
|
|
.filter(filterHandler)
|
|
.filter((item) => !lookupFixedFieldCodes.includes(item.to.fields[0].code))
|
|
.reduce((accumulator, item) => {
|
|
return {
|
|
...accumulator,
|
|
[item.to.fields[0].code]: {
|
|
value: getFromValue(item,context),
|
|
},
|
|
};
|
|
}, {});
|
|
if (record && Object.keys(record).length > 0) {
|
|
console.log(record);
|
|
await client.record.addRecord({
|
|
app:appId,
|
|
record:record
|
|
});
|
|
// await kintone.api(kintone.api.url("/k/v1/record.json", true), "POST", {
|
|
// app: appId,
|
|
// record: record,
|
|
// });
|
|
}
|
|
};
|
|
|
|
const getLookupFixedFieldCodes = async (appId: string) => {
|
|
return await client.app
|
|
.getFormFields({ app: appId })
|
|
.then((resp) =>
|
|
Object.values(resp.properties)
|
|
.filter((f) => (f as Lookup).lookup !== undefined)
|
|
.flatMap((f) => (f as Lookup).lookup.fieldMappings.map((m) => m.field))
|
|
);
|
|
};
|