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( actionNode: IActionNode, event: any, context: IContext ): Promise { this.actionProps = actionNode.actionProps; this.dataMappingProps = actionNode.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) { context.errors.handleError(error,actionNode); 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)) ); };