Files
KintoneAppBuilder/plugin/kintone-addins/src/actions/data-update.ts
2024-07-31 18:28:25 +09:00

335 lines
8.8 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(
actionNode: IActionNode,
event: any,
context: IContext
): Promise<IActionResult> {
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))
);
};