From 08005111773873e7c8ab907d46ce80ac9baadbff Mon Sep 17 00:00:00 2001 From: Edwin Betancourt Date: Fri, 12 Jun 2020 12:07:24 -0400 Subject: [PATCH] feat: Remove context (#508) * Change definition for v-model of fields using reactive store * change custom validateValue to custom and overwrite parsedValue. * Delete unused parameters. * Add queue for persistence * fix: Create entity. * Add return value as array for persistence * Add multiple commit for panel * remove commnets * Change context session to preference. * fix: Load window. * Add support to seekrecord for panel * Set default value to isActive columnName. * set default values. * Separate template mobile and panel desktop with mixin. * set values into panel with first load of records. * fix lookups value and display value. * change `DisplayColumn_${columnName}` to `displayColumnName` property. * fix create entity with default values. * Set default values and fix browser search. * fix context values from SmartBrowser. * fix: Associated process. * set context values to process associated. * fix set values. * fix style field components. * fix send values to server. Co-authored-by: Yamel Senih --- src/api/ADempiere/persistence.js | 8 +- src/api/ADempiere/values.js | 9 +- .../ADempiere/ContextMenu/contextMenuMixin.js | 17 +- src/components/ADempiere/DataTable/index.vue | 41 +- .../DataTable/menu/menuTableMixin.js | 9 +- src/components/ADempiere/Dialog/index.vue | 4 +- .../ADempiere/Field/FieldBinary.vue | 17 +- .../ADempiere/Field/FieldButton.vue | 20 +- src/components/ADempiere/Field/FieldColor.vue | 28 +- src/components/ADempiere/Field/FieldDate.vue | 84 +- src/components/ADempiere/Field/FieldImage.vue | 30 +- .../ADempiere/Field/FieldLocator.vue | 5 +- .../ADempiere/Field/FieldNumber.vue | 45 +- .../ADempiere/Field/FieldSelect.vue | 186 ++- .../ADempiere/Field/FieldSelectMultiple.vue | 9 +- src/components/ADempiere/Field/FieldText.vue | 44 +- .../ADempiere/Field/FieldTextLong.vue | 41 +- src/components/ADempiere/Field/FieldTime.vue | 21 +- src/components/ADempiere/Field/FieldYesNo.vue | 37 +- .../ADempiere/Field/chatTextLong.vue | 16 - src/components/ADempiere/Field/index.vue | 17 +- .../{FieldMixin.js => mixin/mixinField.js} | 110 +- .../ADempiere/Field/mixin/mixinFieldRange.js | 29 + .../ADempiere/Field/mixin/mixinFieldText.js | 10 + .../ADempiere/Field/popover/calculator.vue | 54 +- .../Field/popover/documentStatus.vue | 14 +- .../Field/popover/operatorComparison.vue | 31 +- src/components/ADempiere/Form/formMixin.js | 12 +- src/components/ADempiere/Panel/index.vue | 751 +-------- .../ADempiere/Panel/mainPanelDesktop.vue | 170 ++ .../ADempiere/Panel/mainPanelMixin.js | 542 +++++++ .../ADempiere/Panel/mainPanelMobile.vue | 150 ++ .../ADempiere/WorkflowStatusBar/index.vue | 58 +- src/layout/components/TagsView/index.vue | 2 +- src/store/modules/ADempiere/browser.js | 337 ++-- src/store/modules/ADempiere/browserControl.js | 125 -- .../modules/ADempiere/browserDefinition.js | 198 +++ src/store/modules/ADempiere/calloutControl.js | 7 +- src/store/modules/ADempiere/context.js | 178 --- src/store/modules/ADempiere/data.js | 45 +- src/store/modules/ADempiere/event.js | 2 + src/store/modules/ADempiere/fieldValue.js | 159 ++ .../ADempiere/{form.js => formDefinition.js} | 0 .../{languageControl.js => language.js} | 0 src/store/modules/ADempiere/lookup.js | 50 +- src/store/modules/ADempiere/panel.js | 1013 ++++++------ src/store/modules/ADempiere/persistence.js | 80 + src/store/modules/ADempiere/preference.js | 158 ++ src/store/modules/ADempiere/process.js | 1057 ++++++++++++- src/store/modules/ADempiere/processControl.js | 994 ------------ .../modules/ADempiere/processDefinition.js | 112 ++ .../ADempiere/{reportControl.js => report.js} | 11 +- src/store/modules/ADempiere/window.js | 1391 ++++++++++++----- src/store/modules/ADempiere/windowControl.js | 935 ----------- .../modules/ADempiere/windowDefinition.js | 452 ++++++ src/store/modules/user.js | 6 +- src/utils/ADempiere/contextUtils.js | 220 +-- src/utils/ADempiere/dictionaryUtils.js | 52 +- src/utils/ADempiere/evaluator.js | 25 +- src/utils/ADempiere/lookupFactory.js | 2 + src/utils/ADempiere/valueFormat.js | 82 +- src/utils/ADempiere/valueUtils.js | 67 +- src/views/ADempiere/Browser/index.vue | 55 +- 63 files changed, 5489 insertions(+), 4945 deletions(-) rename src/components/ADempiere/Field/{FieldMixin.js => mixin/mixinField.js} (71%) create mode 100644 src/components/ADempiere/Field/mixin/mixinFieldRange.js create mode 100644 src/components/ADempiere/Field/mixin/mixinFieldText.js create mode 100644 src/components/ADempiere/Panel/mainPanelDesktop.vue create mode 100644 src/components/ADempiere/Panel/mainPanelMixin.js create mode 100644 src/components/ADempiere/Panel/mainPanelMobile.vue delete mode 100644 src/store/modules/ADempiere/browserControl.js create mode 100644 src/store/modules/ADempiere/browserDefinition.js delete mode 100644 src/store/modules/ADempiere/context.js create mode 100644 src/store/modules/ADempiere/fieldValue.js rename src/store/modules/ADempiere/{form.js => formDefinition.js} (100%) rename src/store/modules/ADempiere/{languageControl.js => language.js} (100%) create mode 100644 src/store/modules/ADempiere/persistence.js create mode 100644 src/store/modules/ADempiere/preference.js delete mode 100644 src/store/modules/ADempiere/processControl.js create mode 100644 src/store/modules/ADempiere/processDefinition.js rename src/store/modules/ADempiere/{reportControl.js => report.js} (97%) delete mode 100644 src/store/modules/ADempiere/windowControl.js create mode 100644 src/store/modules/ADempiere/windowDefinition.js diff --git a/src/api/ADempiere/persistence.js b/src/api/ADempiere/persistence.js index 810cc45e..9bb0e890 100644 --- a/src/api/ADempiere/persistence.js +++ b/src/api/ADempiere/persistence.js @@ -6,10 +6,10 @@ import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js' * @param {string} tableName * @param {array} attributesList */ -export function createEntity({ tableName, attributesList }) { +export function createEntity({ tableName, attributes }) { return Instance.call(this).requestCreateEntity({ tableName, - attributesList + attributesList: attributes }) } @@ -20,12 +20,12 @@ export function createEntity({ tableName, attributesList }) { * @param {string} recordUuid * @param {array} attributesList */ -export function updateEntity({ tableName, recordId, recordUuid, attributesList }) { +export function updateEntity({ tableName, recordId, recordUuid, attributes }) { return Instance.call(this).requestUpdateEntity({ tableName, recordId, recordUuid, - attributesList + attributesList: attributes }) } diff --git a/src/api/ADempiere/values.js b/src/api/ADempiere/values.js index 3df5b3dc..d68daebd 100644 --- a/src/api/ADempiere/values.js +++ b/src/api/ADempiere/values.js @@ -8,7 +8,7 @@ import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js' * @param {string} directQuery * @param {string|number} value */ -export function getLookup({ +export function requestLookup({ tableName, directQuery, value @@ -25,16 +25,21 @@ export function getLookup({ * The main attributes that function hope are: * @param {string} tableName * @param {string} query + * @param {Array|} valuesList + * @param {string} pageToken + * @param {number} pageSize */ -export function getLookupList({ +export function requestLookupList({ tableName, query, + valuesList = [], pageToken, pageSize }) { return Instance.call(this).requestListLookupFromReference({ tableName, query, + valuesList, pageToken, pageSize }) diff --git a/src/components/ADempiere/ContextMenu/contextMenuMixin.js b/src/components/ADempiere/ContextMenu/contextMenuMixin.js index 0df754d8..5833d62d 100644 --- a/src/components/ADempiere/ContextMenu/contextMenuMixin.js +++ b/src/components/ADempiere/ContextMenu/contextMenuMixin.js @@ -139,7 +139,7 @@ export const contextMixin = { }) return value.map(fieldItem => { if (fieldItem.componentPath === 'FieldSelect') { - return 'DisplayColumn_' + fieldItem.columnName + return fieldItem.displayColumnName } return fieldItem.columnName }) @@ -174,7 +174,7 @@ export const contextMixin = { }, getOldRouteOfWindow() { if (this.panelType === 'window') { - const oldRoute = this.$store.state.windowControl.windowOldRoute + const oldRoute = this.$store.state.window.windowOldRoute if (!this.isEmptyValue(oldRoute.query.action) && oldRoute.query.action !== 'create-new' && this.$route.query.action === 'create-new') { return oldRoute } @@ -234,7 +234,7 @@ export const contextMixin = { actionContextMenu(event) { switch (event.srcKey) { case 'f2': - this.$store.dispatch('resetPanelToNew', { + this.$store.dispatch('setDefaultValues', { parentUuid: this.parentUuid, containerUuid: this.containerUuid, recordUuid: this.recordUuid, @@ -395,14 +395,15 @@ export const contextMixin = { if (action.type === 'process') { // Add context from view open in process to opening if (action.parentUuidAssociated || action.containerUuidAssociated) { - const contextValues = this.$store.getters.getContextView({ + const attributes = this.$store.getters.getValuesView({ parentUuid: action.parentUuidAssociated, containerUuid: action.containerUuidAssociated }) - if (!this.isEmptyValue(contextValues)) { - this.$store.dispatch('setMultipleContextView', { + + if (!this.isEmptyValue(attributes)) { + this.$store.dispatch('updateValuesOfContainer', { containerUuid: action.uuid, - values: contextValues + attributes }) } } @@ -437,7 +438,7 @@ export const contextMixin = { containerUuid: this.containerUuid, recordUuid: this.recordUuid, panelType: this.panelType, - isNewRecord: action.action === 'resetPanelToNew', + isNewRecord: action.action === 'setDefaultValues', tableName: action.tableName, recordId: action.recordId }) diff --git a/src/components/ADempiere/DataTable/index.vue b/src/components/ADempiere/DataTable/index.vue index 86bc87c0..5162c358 100644 --- a/src/components/ADempiere/DataTable/index.vue +++ b/src/components/ADempiere/DataTable/index.vue @@ -186,7 +186,7 @@ :in-table="true" :metadata-field="{ ...fieldAttributes, - displayColumn: scope.row['DisplayColumn_' + fieldAttributes.columnName], + displayColumn: scope.row[fieldAttributes.displayColumnName], tableIndex: scope.$index, rowKey: scope.row[getterPanel.keyColumn], keyColumn: getterPanel.keyColumn, @@ -470,22 +470,21 @@ export default { isPanelWindow() { return Boolean(this.panelType === 'window') }, - getterContextClientId() { + preferenceClientId() { if (this.isPanelWindow) { - return this.$store.getters.getContextClientId + return this.$store.getters.getPreferenceClientId } return undefined }, isReadOnlyParent() { if (this.isPanelWindow) { - if (this.$store.getters.getContextIsActive(this.parentUuid) === false) { + if (!this.$store.getters.getContainerIsActive(this.parentUuid)) { return true } - if (this.$store.getters.getContextProcessing(this.parentUuid) === true || - this.$store.getters.getContextProcessing(this.parentUuid) === 'Y') { + if (this.$store.getters.getContainerProcessing(this.parentUuid)) { return true } - if (this.$store.getters.getContextProcessed(this.parentUuid)) { + if (this.$store.getters.getContainerProcessed(this.parentUuid)) { return true } } @@ -617,7 +616,7 @@ export default { */ displayedValue(row, field) { if (typeof row[field.columnName] === 'boolean') { - // replace boolean true-false value for 'Yes' or 'Not' + // replace boolean true-false value for 'Yes' or 'Not' ('Si' or 'No' for spanish) return row[field.columnName] ? this.$t('components.switchActiveText') : this.$t('components.switchInactiveText') } else if (field.componentPath === 'FieldDate' || field.componentPath === 'FieldTime') { let cell = row[field.columnName] @@ -634,10 +633,12 @@ export default { displayType: field.displayType, number: row[field.columnName] }) - } else if (field.componentPath === 'FieldSelect' && this.isEmptyValue(row['DisplayColumn_' + field.columnName]) && row[field.columnName] === 0) { + } else if (field.componentPath === 'FieldSelect' && + this.isEmptyValue(row[field.displayColumnName]) && + row[field.columnName] === 0) { return field.defaultValue } - return row['DisplayColumn_' + field.columnName] || row[field.columnName] + return row[field.displayColumnName] || row[field.columnName] }, rowCanBeEdited(record, fieldAttributes) { if (!this.isParent) { @@ -663,28 +664,19 @@ export default { }, isReadOnlyRow(row, field) { // evaluate context - if (this.getterContextClientId !== parseInt(row.AD_Client_ID, 10)) { + if (this.preferenceClientId !== parseInt(row.AD_Client_ID, 10)) { return true } if (fieldIsDisplayed(field)) { - // const fieldReadOnlyAllForm = FIELDS_READ_ONLY_FORM.filter(item => { - // return item.isChangedAllForm && - // Object.prototype.hasOwnProperty.call(row, item.columnName) - // }) - // // columnName: Processed, Processing - // if (fieldReadOnlyAllForm.length) { - // const isReadOnlyAllRow = Boolean(fieldReadOnlyAllForm.find(item => row[item.columnName] === item.valueIsReadOnlyForm)) - // return isReadOnlyAllRow - // } - // columnName: IsActive const fieldReadOnlyForm = FIELDS_READ_ONLY_FORM.find(item => { return !item.isChangedAllForm && + // columnName: IsActive, Processed, Processing Object.prototype.hasOwnProperty.call(row, item.columnName) }) if (fieldReadOnlyForm) { - const isReadOnlyRow = row[fieldReadOnlyForm.columnName] === fieldReadOnlyForm.valueIsReadOnlyForm && field.columnName !== fieldReadOnlyForm.columnName - return isReadOnlyRow + return field.columnName !== fieldReadOnlyForm.columnName && + row[fieldReadOnlyForm.columnName] === fieldReadOnlyForm.valueIsReadOnlyForm } } return false @@ -1078,8 +1070,7 @@ export default { } } } - - diff --git a/src/components/ADempiere/Field/FieldImage.vue b/src/components/ADempiere/Field/FieldImage.vue index 4f2e213f..15062cda 100644 --- a/src/components/ADempiere/Field/FieldImage.vue +++ b/src/components/ADempiere/Field/FieldImage.vue @@ -6,7 +6,7 @@ :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload" :disabled="isDisabled" - :class="'avatar-uploader ' + metadata.cssClassName" + :class="cssClassStyle" > @@ -14,33 +14,21 @@ - diff --git a/src/components/ADempiere/Field/FieldTime.vue b/src/components/ADempiere/Field/FieldTime.vue index e65cf271..89d709b8 100644 --- a/src/components/ADempiere/Field/FieldTime.vue +++ b/src/components/ADempiere/Field/FieldTime.vue @@ -9,7 +9,7 @@ :is-range="isPickerRange" range-separator="-" :placeholder="$t('components.timePlaceholder')" - :class="'time-base ' + metadata.cssClassName" + :class="cssClassStyle" :readonly="Boolean(metadata.readonly)" :disabled="isDisabled" @change="preHandleChange" @@ -21,7 +21,7 @@ diff --git a/src/components/ADempiere/Field/FieldYesNo.vue b/src/components/ADempiere/Field/FieldYesNo.vue index add2c80f..d9775460 100644 --- a/src/components/ADempiere/Field/FieldYesNo.vue +++ b/src/components/ADempiere/Field/FieldYesNo.vue @@ -4,7 +4,7 @@ v-model="value" :inactive-text="$t('components.switchInactiveText')" :active-text="$t('components.switchActiveText')" - :class="'custom-field-yes-no ' + metadata.cssClassName" + :class="cssClassStyle" :true-value="true" :false-value="false" :disabled="isDisabled" @@ -17,7 +17,8 @@ - diff --git a/src/components/ADempiere/Panel/mainPanelMixin.js b/src/components/ADempiere/Panel/mainPanelMixin.js new file mode 100644 index 00000000..67c178bf --- /dev/null +++ b/src/components/ADempiere/Panel/mainPanelMixin.js @@ -0,0 +1,542 @@ +import FieldDefinition from '@/components/ADempiere/Field' +import FilterFields from '@/components/ADempiere/Panel/filterFields' +import { fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils.js' +import { parsedValueComponent } from '@/utils/ADempiere/valueUtils.js' +import { convertObjectToKeyValue } from '@/utils/ADempiere/valueFormat.js' + +export const mainPanelMixin = { + name: 'MainPanelMixin', + components: { + FieldDefinition, + FilterFields + }, + props: { + parentUuid: { + type: String, + default: undefined + }, + containerUuid: { + type: String, + required: true + }, + metadata: { + type: Object, + default: () => {} + }, + // tab type group + groupTab: { + type: Object, + default: () => ({ + groupType: '', + groupName: '' + }) + }, + panelType: { + type: String, + default: 'window' + }, + isAdvancedQuery: { + type: Boolean, + default: false + }, + isShowedRecordNavigation: { + type: Boolean, + default: false + } + }, + data() { + return { + panelMetadata: {}, + fieldList: [], // groups list of fields + dataRecords: {}, + isLoadPanel: false, + isLoadRecord: false, + uuidRecord: this.$route.query.action, + fieldGroups: [], + firstGroup: {}, + groupsView: 0, + tagTitle: { + base: this.$route.meta.title, + action: '' + } + } + }, + computed: { + shadowGroup() { + if (this.isMobile) { + return 'never' + } + return 'hover' + }, + optionCRUD() { + return this.isEmptyValue(this.uuidRecord) ? 'create-new' : this.uuidRecord + }, + isPanelWindow() { + return this.panelType === 'window' + }, + panelAttributes() { + return { + recordUuid: this.uuidRecord, + optionCRUD: this.optionCRUD, + isShowedRecordNavigation: this.isShowedRecordNavigation, + isProcessingContext: this.getContainerProcessing, + isProcessedContext: this.getContainerProcessed + } + }, + getContainerProcessing() { + if (this.panelType === 'window' && !this.isAdvancedQuery) { + return this.$store.getters.getContainerProcessing(this.parentUuid) + } + return false + }, + getContainerProcessed() { + if (this.panelType === 'window' && !this.isAdvancedQuery) { + return this.$store.getters.getContainerProcessed(this.parentUuid) + } + return false + }, + getterPanel() { + return this.$store.getters.getPanel(this.containerUuid, this.isAdvancedQuery) + }, + fieldsList() { + let panel = this.panelMetadata + if (!this.isEmptyValue(panel) && panel.fieldList) { + return panel.fieldList + } + panel = this.getterPanel + if (panel) { + return panel.fieldList + } + return undefined + }, + isMobile() { + return this.$store.state.app.device === 'mobile' + }, + getterDataStore() { + if (this.isPanelWindow) { + return this.$store.getters.getDataRecordAndSelection(this.containerUuid) + } + return { + recordCount: 0, + isLoaded: false, + record: [] + } + }, + getterIsLoadedRecord() { + return this.getterDataStore.isLoaded + }, + classCards() { + if (this.isMobile || this.fieldGroups.length < 2 || this.isShowedRecordNavigation) { + return 'cards-not-group' + } + return 'cards-in-group' + } + }, + watch: { + // used only panel modal (process associated in browser or window) + containerUuid() { + if (['report', 'process'].includes(this.panelType)) { + this.generatePanel(this.metadata.fieldList) + } + }, + '$route.query.action'(newValue, oldValue) { + // used in field, if uuid record or different create-new, field is read only + this.uuidRecord = newValue + + if (newValue !== oldValue && this.isPanelWindow) { + this.changePanelRecord(newValue) + } + }, + isLoadPanel(value) { + if (value) { + this.readParameters() + } + } + }, + created() { + // get fields with uuid + this.getPanel() + }, + methods: { + /** + * Get the tab object with all its attributes as well as the fields it contains + */ + getPanel() { + const panel = this.getterPanel + if (!this.isEmptyValue(panel) && panel.fieldList) { + this.panelMetadata = panel + const fieldsList = panel.fieldList + if (fieldsList && Array.isArray(fieldsList)) { + this.generatePanel(fieldsList) + } + } else { + this.$store.dispatch('getPanelAndFields', { + parentUuid: this.parentUuid, + containerUuid: this.containerUuid, + panelType: this.panelType, + panelMetadata: this.metadata, + isAdvancedQuery: this.isAdvancedQuery + }).then(panelResponse => { + this.panelMetadata = panelResponse + this.generatePanel(panelResponse.fieldList) + }).catch(error => { + console.warn(`Field Load Error: ${error.message}. Code: ${error.code}.`) + }) + } + }, + generatePanel(fieldsList) { + // order and assign groups + this.fieldList = fieldsList + if (fieldsList.length) { + this.fieldGroups = this.sortAndGroup(fieldsList) + } + let firstGroup + if (this.fieldGroups[0] && this.fieldGroups[0].groupFinal === '') { + firstGroup = this.fieldGroups[0] + this.fieldGroups.shift() + } + this.firstGroup = firstGroup + + this.isLoadPanel = true + }, + /** + * TODO: Delete route parameters after reading them + */ + readParameters() { + const parameters = { + isLoadAllRecords: true, + isReference: false, + isNewRecord: false, + isWindow: true, + criteria: {} + } + const route = this.$route + if (this.isPanelWindow) { + // TODO: use action notifyPanelChange with isShowedField in true + this.fieldsList.forEach(fieldItem => { + if (Object.prototype.hasOwnProperty.call(route.query, fieldItem.columnName) && !fieldItem.isAdvancedQuery) { + fieldItem.isShowedFromUser = true + fieldItem.value = parsedValueComponent({ + componentPath: fieldItem.componentPath, + columnName: fieldItem.columnName, + value: route.query[fieldItem.columnName], + displayType: fieldItem.displayType, + isIdentifier: fieldItem.columnName.includes('_ID') + }) + if (String(route.query.isAdvancedQuery) === String(fieldItem.isAdvancedQuery)) { + fieldItem.value = parsedValueComponent({ + componentPath: fieldItem.componentPath, + columnName: fieldItem.columnName, + value: route.query[fieldItem.columnName], + displayType: fieldItem.displayType, + isIdentifier: fieldItem.columnName.includes('_ID') + }) + if (fieldItem.isRange && this.$route.query[`${fieldItem.columnName}_To`]) { + fieldItem.valueTo = parsedValueComponent({ + componentPath: fieldItem.componentPath, + columnName: fieldItem.componentPath, + value: route.query[`${fieldItem.columnName}_To`], + displayType: fieldItem.displayType, + isIdentifier: fieldItem.columnName.includes('_ID') + }) + } + } + } + }) + + if (route.query.action && route.query.action === 'reference') { + const referenceInfo = this.$store.getters.getReferencesInfo({ + windowUuid: this.parentUuid, + recordUuid: route.query.recordUuid, + referenceUuid: route.query.referenceUuid + }) + route.params.isReadParameters = true + parameters.isLoadAllRecords = false + parameters.isReference = true + parameters.referenceUuid = referenceInfo.uuid + parameters.referenceWhereClause = referenceInfo.whereClause + } else if (route.query.action && route.query.action === 'create-new') { + parameters.isNewRecord = true + } else if (route.query.action && route.query.action === 'criteria') { + route.params.isReadParameters = true + Object.keys(route.params).forEach(param => { + if (!this.isEmptyValue(route.params[param])) { + parameters.criteria[param] = route.params[param] + } + }) + } else if (route.query.action && route.query.action === 'listRecords') { + parameters.isLoadAllRecords = true + route.params.isReadParameters = true + } else if (!this.isEmptyValue(route.query.action) && + !['create-new', 'reference', 'advancedQuery', 'criteria', 'listRecords'].includes(route.query.action)) { + parameters.isLoadAllRecords = false + parameters.value = route.query.action + parameters.tableName = this.metadata.tableName + parameters.columnName = 'UUID' + route.params.isReadParameters = true + } + // Only call get data if panel type is window + if (!Object.prototype.hasOwnProperty.call(route.params, 'isReadParameters') || route.params.isReadParameters) { + this.getData(parameters) + } + let viewTitle = '' + if (route.query && !this.isEmptyValue(route.query.action)) { + viewTitle = route.query.action + } + this.setTagsViewTitle(viewTitle) + } else { + if (this.panelType === 'table' && route.query.action === 'advancedQuery') { + // TODO: use action notifyPanelChange with isShowedField in true + this.fieldList.forEach(fieldItem => { + if (Object.prototype.hasOwnProperty.call(route.query, fieldItem.columnName) && fieldItem.isAdvancedQuery) { + fieldItem.isShowedFromUser = true + + if (route.query.action === 'advancedQuery' && fieldItem.isAdvancedQuery) { + this.dataRecords[fieldItem.columnName] = parsedValueComponent({ + componentPath: fieldItem.componentPath, + columnName: fieldItem.columnName, + value: route.query[fieldItem.columnName], + isIdentifier: fieldItem.columnName.includes('_ID') + }) + if (fieldItem.isRange && route.query[`${fieldItem.columnName}_To`]) { + this.dataRecords[fieldItem.columnName] = parsedValueComponent({ + componentPath: fieldItem.componentPath, + columnName: fieldItem.columnName, + value: route.query[`${fieldItem.columnName}_To`], + isIdentifier: fieldItem.columnName.includes('_ID') + }) + } + } + } + }) + parameters.isWindow = false + this.$store.dispatch('notifyPanelChange', { + parentUuid: this.parentUuid, + containerUuid: this.containerUuid, + isAdvancedQuery: route.query.action === 'advancedQuery', + newValues: this.dataRecords, + isSendToServer: true, + isSendCallout: false, + fieldList: this.fieldList, + panelType: this.panelType + }) + } else if (['process', 'browser'].includes(this.panelType)) { + if (!this.isEmptyValue(route.query)) { + this.$store.dispatch('notifyPanelChange', { + containerUuid: this.containerUuid, + newValues: route.query, + isShowedField: true, + isSendCallout: false, + panelType: this.panelType + }) + parameters.isWindow = false + } + } + } + }, + /** + * @param {object} parameters parameters to condition the data query + */ + getData(parameters) { + if (parameters.isWindow && this.isPanelWindow && !this.getterIsLoadedRecord) { + this.$store.dispatch('getDataListTab', { + parentUuid: this.parentUuid, + containerUuid: this.containerUuid, + isLoadAllRecords: parameters.isLoadAllRecords, + isReference: parameters.isReference, + referenceWhereClause: parameters.referenceWhereClause, + columnName: parameters.columnName, + value: parameters.value, + criteria: parameters.criteria + }) + .then(response => { + let action = 'create-new' + let params = this.$route.params + if (response.length && !parameters.isNewRecord) { + this.dataRecords = response[0] + const recordId = this.dataRecords[`${this.metadata.tableName}_ID`] + params = { + ...params, + tableName: this.metadata.tableName, + recordId + } + if (this.$route.query.action === 'reference') { + action = 'reference' + } else { + // 'criteria' + action = this.dataRecords.UUID + } + let viewTitle = '' + if (this.$route.query && !this.isEmptyValue(this.$route.query.action)) { + viewTitle = this.$route.query.action + } + this.setTagsViewTitle(viewTitle) + this.isLoadRecord = true + } + + this.$router.push({ + name: this.$route.name, + params, + query: { + ...this.$route.query, + action + } + }).catch(error => { + console.info(`Panel Component: ${error.name}, ${error.message}`) + }) + + if (action === 'create-new') { + this.$store.dispatch('setDefaultValues', { + panelType: this.panelType, + parentUuid: this.parentUuid, + containerUuid: this.containerUuid, + isNewRecord: true + }) + } else { + const attributes = convertObjectToKeyValue({ + object: this.dataRecords + }) + this.$store.dispatch('notifyPanelChange', { + parentUuid: this.parentUuid, + containerUuid: this.containerUuid, + attributes + }) + } + }) + .catch(error => { + console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) + }) + } + }, + /** + * Group the arrangement into groups of columns that they contain, it must + * be grouped after having the order + * @param {array} fieldsList + * @return {array} groupsList + * TODO: Save into store to dont regenerate + */ + sortAndGroup(fieldsList) { + if (this.isEmptyValue(fieldsList)) { + return + } + let groupsList = [{ + groupFinal: '', + metadataFields: fieldsList + }] + + // reduce, create array with number groupAssigned element comun + if (this.isPanelWindow) { + groupsList = fieldsList + .reduce((groupsList, currentValue) => { + if (!groupsList.includes(currentValue.groupAssigned)) { + groupsList.push(currentValue.groupAssigned) + } + return groupsList + }, []) + .map(itemGroup => { + return { + groupFinal: itemGroup, + metadataFields: fieldsList.filter(itemField => { + return itemField.groupAssigned === itemGroup + }) + } + }) + } + + // count and add the field numbers according to your group + groupsList.forEach(groupFields => { + const typeG = groupFields.metadataFields[0].typeGroupAssigned + groupFields.typeGroup = typeG + + const fieldsDisplayed = groupFields.metadataFields.filter(field => { + return fieldIsDisplayed(field) + }) + + if ((this.groupTab.groupType === 'T' && this.groupTab.groupName === groupFields.groupFinal) || + (this.groupTab.groupType !== 'T' && groupFields.typeGroup !== 'T')) { + this.groupsView = this.groupsView + 1 + } + groupFields.activeFields = fieldsDisplayed.length + }) + + return groupsList + }, + setTagsViewTitle(actionValue) { + if (actionValue !== 'create-new' && !this.isEmptyValue(actionValue) && this.panelMetadata.isDocument && this.getterDataStore.isLoaded) { + this.$store.dispatch('listWorkflows', this.metadata.tableName) + this.$store.dispatch('listDocumentStatus', { + recordUuid: this.$route.query.action, + tableName: this.metadata.tableName + }) + } + if (actionValue === 'create-new' || this.isEmptyValue(actionValue)) { + this.tagTitle.action = this.$t('tagsView.newRecord') + } else if (actionValue === 'advancedQuery') { + this.tagTitle.action = this.$t('tagsView.advancedQuery') + } else { + const { identifierColumns } = this.panelMetadata + if (!this.isEmptyValue(identifierColumns)) { + if (this.dataRecords[identifierColumns[0]]) { + this.tagTitle.action = this.dataRecords[identifierColumns[0]] + } else { + const field = this.fieldList.find(fieldItem => fieldItem.isIdentifier) + this.tagTitle.action = field.value + } + } else { + this.tagTitle.action = this.$t('tagsView.seeRecord') + } + } + if (this.isPanelWindow) { + this.$store.dispatch('tagsView/updateVisitedView', { + ...this.$route, + title: `${this.tagTitle.base} - ${this.tagTitle.action}` + }) + } + }, + changePanelRecord(uuidRecord) { + if (!['create-new', 'reference', 'advancedQuery', 'criteria', 'listRecords'].includes(uuidRecord)) { + this.$store.dispatch('seekRecord', { + parentUuid: this.parentUuid, + containerUuid: this.containerUuid, + recordUuid: uuidRecord + }).then(() => { + if (this.panelMetadata.isTabsChildren) { + // delete records tabs children when change record uuid + this.$store.dispatch('deleteRecordContainer', { + viewUuid: this.parentUuid, + withOut: [this.containerUuid] + }) + } + }) + } + this.setTagsViewTitle(uuidRecord) + if (this.$route.query && this.$route.query.action === 'create-new') { + this.setFocus() + } + const currentRecord = this.getterDataStore.record.find(record => record.UUID === uuidRecord) + this.$store.dispatch('currentRecord', currentRecord) + }, + async setFocus() { + return new Promise(resolve => { + const fieldFocus = this.fieldsList.find(itemField => { + if (itemField.handleRequestFocus) { + return true + } + if (Object.prototype.hasOwnProperty.call(this.$refs, itemField.columnName)) { + if (fieldIsDisplayed(itemField) && + !itemField.isReadOnly && + itemField.isUpdateable && + itemField.componentPath !== 'FieldSelect') { + return true + } + } + }) + if (fieldFocus) { + this.$refs[fieldFocus.columnName][0].focusField() + } + resolve() + return + }) + } + } +} diff --git a/src/components/ADempiere/Panel/mainPanelMobile.vue b/src/components/ADempiere/Panel/mainPanelMobile.vue new file mode 100644 index 00000000..e61c3fdc --- /dev/null +++ b/src/components/ADempiere/Panel/mainPanelMobile.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/src/components/ADempiere/WorkflowStatusBar/index.vue b/src/components/ADempiere/WorkflowStatusBar/index.vue index 11510be5..fbb8d7ed 100644 --- a/src/components/ADempiere/WorkflowStatusBar/index.vue +++ b/src/components/ADempiere/WorkflowStatusBar/index.vue @@ -177,35 +177,35 @@ export default { } }, documentActionChange(value) { - this.$store.dispatch('notifyFieldChange', { - parentUuid: this.parentUuid, - containerUuid: this.containerUuid, - columnName: 'DocAction', - isSendToServer: true, - newValue: value - }) - .then(response => { - const actionProcess = this.$store.getters.getOrders - this.$store.dispatch('startProcess', { - action: { - uuid: actionProcess.uuid, - id: actionProcess.id, - name: actionProcess.name - }, // process metadata - tableName: this.$route.params.tableName, - recordId: this.$route.params.recordId, - recordUuid: this.$route.query.action, - parametersList: [{ - columnName: 'DocAction', - value: this.valueActionDocument - }], - isActionDocument: true, - parentUuid: this.parentUuid, - panelType: this.panelType, - containerUuid: this.containerUuid// determinate if get table name and record id (window) or selection (browser) - }) - this.valueActionDocument = '' - }) + // this.$store.dispatch('notifyFieldChange', { + // parentUuid: this.parentUuid, + // containerUuid: this.containerUuid, + // columnName: 'DocAction', + // isSendToServer: true, + // newValue: value + // }) + // .then(response => { + // const actionProcess = this.$store.getters.getOrders + // this.$store.dispatch('startProcess', { + // action: { + // uuid: actionProcess.uuid, + // id: actionProcess.id, + // name: actionProcess.name + // }, // process metadata + // tableName: this.$route.params.tableName, + // recordId: this.$route.params.recordId, + // recordUuid: this.$route.query.action, + // parametersList: [{ + // columnName: 'DocAction', + // value: this.valueActionDocument + // }], + // isActionDocument: true, + // parentUuid: this.parentUuid, + // panelType: this.panelType, + // containerUuid: this.containerUuid// determinate if get table name and record id (window) or selection (browser) + // }) + // this.valueActionDocument = '' + // }) } } } diff --git a/src/layout/components/TagsView/index.vue b/src/layout/components/TagsView/index.vue index 140f114f..bdf9931f 100644 --- a/src/layout/components/TagsView/index.vue +++ b/src/layout/components/TagsView/index.vue @@ -203,7 +203,7 @@ export default { this.$store.dispatch('setWindowOldRoute') } - this.$store.dispatch('resetPanelToNew', { + this.$store.dispatch('setDefaultValues', { parentUuid, containerUuid, panelType: view.meta.type, diff --git a/src/store/modules/ADempiere/browser.js b/src/store/modules/ADempiere/browser.js index 5014a6c0..e1bdaf7d 100644 --- a/src/store/modules/ADempiere/browser.js +++ b/src/store/modules/ADempiere/browser.js @@ -1,192 +1,171 @@ -import { getBrowser as getBrowserMetadata } from '@/api/ADempiere/dictionary' -import { showMessage } from '@/utils/ADempiere/notification' +import { getBrowserSearch } from '@/api/ADempiere/browser' import { isEmptyValue } from '@/utils/ADempiere/valueUtils' -import { generateField } from '@/utils/ADempiere/dictionaryUtils' -import router from '@/router' +import { parseContext } from '@/utils/ADempiere/contextUtils' +import { showMessage } from '@/utils/ADempiere/notification' +import { fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils' import language from '@/lang' -const browser = { - state: { - browser: [] - }, - mutations: { - addBrowser(state, payload) { - state.browser.push(payload) - }, - dictionaryResetCacheBrowser(state) { - state.browser = [] - }, - changeBrowserAttribute(state, payload) { - let value = payload.attributeValue - if (payload.attributeNameControl) { - value = payload.browser[payload.attributeNameControl] - } - payload.browser[payload.attributeName] = value - } - }, +const browserControl = { actions: { - getBrowserFromServer({ commit, dispatch }, { + browserActionPerformed({ dispatch, getters }, { containerUuid, - browserId, - routeToDelete + field, + value }) { - return new Promise(resolve => { - getBrowserMetadata({ - uuid: containerUuid, - id: browserId + const fieldsEmpty = getters.getFieldListEmptyMandatory({ + containerUuid, + fieldsList: getters.getFieldsListFromPanel(containerUuid) + }) + if (!isEmptyValue(fieldsEmpty)) { + showMessage({ + message: language.t('notifications.mandatoryFieldMissing') + fieldsEmpty, + type: 'info' }) - .then(browserResponse => { - const panelType = 'browser' - const additionalAttributes = { - containerUuid, - panelType, - isEvaluateValueChanges: true - } - const { - query, - whereClause, - process - } = browserResponse - - // Convert from gRPC - const fieldsRangeList = [] - let isShowedCriteria = false - let awaitForValues = 0 - let fieldsList = browserResponse.fieldsList.map((fieldItem, index) => { - const someAttributes = { - ...additionalAttributes, - fieldListIndex: index - } - const field = generateField({ - fieldToGenerate: fieldItem, - moreAttributes: someAttributes, - isSOTrxMenu: routeToDelete.meta.isSOTrx - }) - // Add new field if is range number - if (field.isRange && field.componentPath === 'FieldNumber') { - const fieldRange = generateField({ - fieldToGenerate: fieldItem, - moreAttributes: someAttributes, - typeRange: true - }) - if (!isEmptyValue(fieldRange.value)) { - fieldRange.isShowedFromUser = true - } - fieldsRangeList.push(fieldRange) - } - - // Only isQueryCriteria fields with values, displayed in main panel - if (field.isQueryCriteria) { - if (field.isSQLValue) { - isShowedCriteria = true - field.isShowedFromUser = true - awaitForValues++ - } - if (query.includes(`@${field.columnName}@`) || - query.includes(`@${field.columnName}_To@`) || - whereClause.includes(`@${field.columnName}@`) || - whereClause.includes(`@${field.columnName}_To@`)) { - field.isMandatory = true - field.isMandatoryFromLogic = true - field.isShowedFromUser = true - } - - if (isEmptyValue(field.value)) { - // isMandatory params to showed search criteria - if (field.isMandatory || field.isMandatoryFromLogic) { - isShowedCriteria = true - } - } else { - // with value - field.isShowedFromUser = true - } - } - - return field - }) - fieldsList = fieldsList.concat(fieldsRangeList) - - // Panel for save on store - const newBrowser = { - ...browserResponse, - containerUuid, - fieldList: fieldsList, - panelType, - // app attributes - awaitForValues, // control to values - awaitForValuesToQuery: awaitForValues, // get values from request search - isShowedCriteria, - isShowedTotals: true - } - - commit('addBrowser', newBrowser) - dispatch('addPanel', newBrowser) - - resolve(newBrowser) - - // Convert from gRPC process list - const actions = [] - if (process) { - actions.push({ - type: 'process', - panelType: 'process', - uuid: process.uuid, - name: process.name, - description: process.description, - isReport: process.isReport, - isDirectPrint: process.isDirectPrint, - containerUuidAssociated: containerUuid, - panelTypeAssociated: panelType - }) - // TODO: No list of parameters - // // add process associated in vuex store - // dispatch('addProcessAssociated', { - // processToGenerate: process, - // containerUuidAssociated: containerUuid - // }) - } - // Add process menu - dispatch('setContextMenu', { - containerUuid, - actions - }) - }) - .catch(error => { - router.push({ path: '/dashboard' }) - dispatch('tagsView/delView', routeToDelete) - showMessage({ - message: language.t('login.unexpectedError'), - type: 'error' - }) - console.warn(`Dictionary Browser - Error ${error.code}: ${error.message}.`) - }) - }) - }, - changeBrowserAttribute({ commit, getters }, { - containerUuid, - browser, - attributeName, - attributeNameControl, - attributeValue - }) { - if (isEmptyValue(browser)) { - browser = getters.getBrowser(containerUuid) + return } - commit('changeBrowserAttribute', { - browser, - attributeName, - attributeValue, - attributeNameControl + + // Validate if a field is called and visible + if (fieldIsDisplayed(field)) { + let isReadyForQuery = true + if (field.isSQLValue) { + const panel = getters.getPanel(containerUuid) + let awaitForValuesToQuery = panel.awaitForValuesToQuery + awaitForValuesToQuery-- + dispatch('changeBrowserAttribute', { + containerUuid, + attributeName: 'awaitForValuesToQuery', + attributeValue: awaitForValuesToQuery + }) + if (awaitForValuesToQuery === 0) { + if (panel.isShowedCriteria) { + dispatch('changeBrowserAttribute', { + containerUuid, + attributeName: 'isShowedCriteria', + attributeValue: false + }) + } + } else if (awaitForValuesToQuery > 0) { + isReadyForQuery = false + } + } + if (isReadyForQuery && !field.dependentFieldsList.length) { + dispatch('getBrowserSearch', { + containerUuid, + isClearSelection: true + }) + } + } + }, + // Search with query criteria + getBrowserSearch({ dispatch, rootGetters }, { + containerUuid, + isClearSelection = false + }) { + showMessage({ + title: language.t('notifications.loading'), + message: language.t('notifications.searching'), + type: 'info' }) - } - }, - getters: { - getBrowser: (state) => (browserUuid) => { - return state.browser.find( - item => item.uuid === browserUuid - ) + const allData = rootGetters.getDataRecordAndSelection(containerUuid) + // deletes the data from the container to replace it and to report the searches in the table + dispatch('deleteRecordContainer', { + viewUuid: containerUuid + }) + + const browser = rootGetters.getBrowser(containerUuid) + // parameters isQueryCriteria + const parametersList = rootGetters.getParametersToServer({ + containerUuid, + fieldList: browser.fieldList + }) + + let parsedQuery = browser.query + if (!isEmptyValue(parsedQuery) && parsedQuery.includes('@')) { + parsedQuery = parseContext({ + containerUuid, + value: parsedQuery, + isBooleanToString: true + }).value + } + + let parsedWhereClause = browser.whereClause + if (!isEmptyValue(parsedWhereClause) && parsedWhereClause.includes('@')) { + parsedWhereClause = parseContext({ + containerUuid, + value: parsedWhereClause, + isBooleanToString: true + }).value + } + + let nextPageToken + if (!isEmptyValue(allData.nextPageToken)) { + nextPageToken = allData.nextPageToken + '-' + allData.pageNumber + } + + // Add validation compare browserSearchQueryParameters + return getBrowserSearch({ + uuid: containerUuid, + query: parsedQuery, + whereClause: parsedWhereClause, + orderByClause: browser.orderByClause, + parametersList, + nextPageToken: nextPageToken + }) + .then(browserSearchResponse => { + const recordsList = browserSearchResponse.recordsList.map(itemRecord => { + return { + ...itemRecord.values, + // datatables attributes + isNew: false, + isEdit: false, + isSelected: false, + isReadOnlyFromRow: false + } + }) + + let selection = allData.selection + if (isClearSelection) { + selection = [] + } + + let token = browserSearchResponse.nextPageToken + if (token !== undefined) { + token = token.slice(0, -2) + } + + dispatch('setRecordSelection', { + containerUuid, + record: recordsList, + pageNumber: rootGetters.getPageNumber(containerUuid), + selection: selection, + recordCount: browserSearchResponse.recordCount, + nextPageToken: token + }) + showMessage({ + title: language.t('notifications.succesful'), + message: language.t('notifications.succcessSearch'), + type: 'success' + }) + return recordsList + }) + .catch(error => { + // Set default registry values so that the table does not say loading, + // there was already a response from the server + dispatch('setRecordSelection', { + containerUuid, + panelType: 'browser' + }) + + showMessage({ + title: language.t('notifications.error'), + message: language.t('notifications.errorSearch'), + summary: error.message, + type: 'error' + }) + console.warn(`Error getting browser search: ${error.message}. Code: ${error.code}.`) + }) } } } -export default browser +export default browserControl diff --git a/src/store/modules/ADempiere/browserControl.js b/src/store/modules/ADempiere/browserControl.js deleted file mode 100644 index 1c7a0018..00000000 --- a/src/store/modules/ADempiere/browserControl.js +++ /dev/null @@ -1,125 +0,0 @@ -import { getBrowserSearch } from '@/api/ADempiere/browser' -import { isEmptyValue } from '@/utils/ADempiere/valueUtils' -import { parseContext } from '@/utils/ADempiere/contextUtils' -import { showMessage } from '@/utils/ADempiere/notification' -import language from '@/lang' - -const browserControl = { - actions: { - /** - * Search with query criteria - * @param {string} containerUuid, browser to search record data - * @param {boolean} isClearSelection, clear selection after search - */ - getBrowserSearch({ dispatch, rootGetters }, { - containerUuid, - isClearSelection = false - }) { - showMessage({ - title: language.t('notifications.loading'), - message: language.t('notifications.searching'), - type: 'info' - }) - const allData = rootGetters.getDataRecordAndSelection(containerUuid) - // deletes the data from the container to replace it and to report the searches in the table - dispatch('deleteRecordContainer', { - viewUuid: containerUuid - }) - - const browser = rootGetters.getBrowser(containerUuid) - // parameters isQueryCriteria - const parametersList = rootGetters.getParametersToServer({ - containerUuid, - fieldList: browser.fieldList - }) - - let parsedQuery = browser.query - if (!isEmptyValue(parsedQuery) && parsedQuery.includes('@')) { - parsedQuery = parseContext({ - containerUuid, - value: parsedQuery, - isBooleanToString: true - }).value - } - - let parsedWhereClause = browser.whereClause - if (!isEmptyValue(parsedWhereClause) && parsedWhereClause.includes('@')) { - parsedWhereClause = parseContext({ - containerUuid, - value: parsedWhereClause, - isBooleanToString: true - }).value - } - - let nextPageToken - if (!isEmptyValue(allData.nextPageToken)) { - nextPageToken = allData.nextPageToken + '-' + allData.pageNumber - } - - // Add validation compare browserSearchQueryParameters - return getBrowserSearch({ - uuid: containerUuid, - query: parsedQuery, - whereClause: parsedWhereClause, - orderByClause: browser.orderByClause, - parametersList, - nextPageToken: nextPageToken - }) - .then(browserSearchResponse => { - const recordsList = browserSearchResponse.recordsList.map(itemRecord => { - return { - ...itemRecord.values, - // datatables attributes - isNew: false, - isEdit: false, - isSelected: false, - isReadOnlyFromRow: false - } - }) - - let selection = allData.selection - if (isClearSelection) { - selection = [] - } - - let token = browserSearchResponse.nextPageToken - if (token !== undefined) { - token = token.slice(0, -2) - } - - dispatch('setRecordSelection', { - containerUuid, - record: recordsList, - pageNumber: rootGetters.getPageNumber(containerUuid), - selection: selection, - recordCount: browserSearchResponse.recordCount, - nextPageToken: token - }) - showMessage({ - title: language.t('notifications.succesful'), - message: language.t('notifications.succcessSearch'), - type: 'success' - }) - return recordsList - }) - .catch(error => { - // Set default registry values so that the table does not say loading, - // there was already a response from the server - dispatch('setRecordSelection', { - containerUuid, - panelType: 'browser' - }) - - showMessage({ - title: language.t('notifications.error'), - message: language.t('notifications.errorSearch'), - summary: error.message, - type: 'error' - }) - console.warn(`Error getting browser search: ${error.message}. Code: ${error.code}.`) - }) - } - } -} - -export default browserControl diff --git a/src/store/modules/ADempiere/browserDefinition.js b/src/store/modules/ADempiere/browserDefinition.js new file mode 100644 index 00000000..12e33e5f --- /dev/null +++ b/src/store/modules/ADempiere/browserDefinition.js @@ -0,0 +1,198 @@ +import { getBrowser as getBrowserMetadata } from '@/api/ADempiere/dictionary' +import { showMessage } from '@/utils/ADempiere/notification' +import { isEmptyValue } from '@/utils/ADempiere/valueUtils' +import { generateField } from '@/utils/ADempiere/dictionaryUtils' +import router from '@/router' +import language from '@/lang' + +const browser = { + state: { + browser: [] + }, + mutations: { + addBrowser(state, payload) { + state.browser.push(payload) + }, + dictionaryResetCacheBrowser(state) { + state.browser = [] + }, + changeBrowserAttribute(state, payload) { + let value = payload.attributeValue + if (payload.attributeNameControl) { + value = payload.browser[payload.attributeNameControl] + } + payload.browser[payload.attributeName] = value + } + }, + actions: { + /** + * Get Smart Browser metadata from server + * @param {string} containerUuid + * @param {number} browserId + * @param {object} routeToDelete, route to close in tagView when fail + */ + getBrowserFromServer({ commit, dispatch }, { + containerUuid, + browserId, + routeToDelete + }) { + return new Promise(resolve => { + getBrowserMetadata({ + uuid: containerUuid, + id: browserId + }) + .then(browserResponse => { + const panelType = 'browser' + const additionalAttributes = { + containerUuid, + panelType, + isEvaluateValueChanges: true + } + const { + query, + whereClause, + process + } = browserResponse + + // Convert from gRPC + const fieldsRangeList = [] + let isShowedCriteria = false + let awaitForValues = 0 + let fieldsList = browserResponse.fieldsList.map((fieldItem, index) => { + const someAttributes = { + ...additionalAttributes, + fieldListIndex: index + } + const field = generateField({ + fieldToGenerate: fieldItem, + moreAttributes: someAttributes, + isSOTrxMenu: routeToDelete.meta.isSOTrx + }) + // Add new field if is range number + if (field.isRange && field.componentPath === 'FieldNumber') { + const fieldRange = generateField({ + fieldToGenerate: fieldItem, + moreAttributes: someAttributes, + typeRange: true + }) + if (!isEmptyValue(fieldRange.value)) { + fieldRange.isShowedFromUser = true + } + fieldsRangeList.push(fieldRange) + } + + // Only isQueryCriteria fields with values, displayed in main panel + if (field.isQueryCriteria) { + if (field.isSQLValue) { + isShowedCriteria = true + field.isShowedFromUser = true + awaitForValues++ + } + if (query.includes(`@${field.columnName}@`) || + query.includes(`@${field.columnName}_To@`) || + whereClause.includes(`@${field.columnName}@`) || + whereClause.includes(`@${field.columnName}_To@`)) { + field.isMandatory = true + field.isMandatoryFromLogic = true + field.isShowedFromUser = true + } + + if (isEmptyValue(field.value)) { + // isMandatory params to showed search criteria + if (field.isMandatory || field.isMandatoryFromLogic) { + isShowedCriteria = true + } + } else { + // with value + field.isShowedFromUser = true + } + } + + return field + }) + fieldsList = fieldsList.concat(fieldsRangeList) + + // Panel for save on store + const newBrowser = { + ...browserResponse, + containerUuid, + fieldList: fieldsList, + panelType, + // app attributes + awaitForValues, // control to values + awaitForValuesToQuery: awaitForValues, // get values from request search + isShowedCriteria, + isShowedTotals: true + } + + commit('addBrowser', newBrowser) + dispatch('addPanel', newBrowser) + + resolve(newBrowser) + + // Convert from gRPC process list + const actions = [] + if (process) { + actions.push({ + type: 'process', + panelType: 'process', + uuid: process.uuid, + name: process.name, + description: process.description, + isReport: process.isReport, + isDirectPrint: process.isDirectPrint, + containerUuidAssociated: containerUuid, + panelTypeAssociated: panelType + }) + // TODO: No list of parameters + // // add process associated in vuex store + // dispatch('addProcessAssociated', { + // processToGenerate: process, + // containerUuidAssociated: containerUuid + // }) + } + // Add process menu + dispatch('setContextMenu', { + containerUuid, + actions + }) + }) + .catch(error => { + router.push({ path: '/dashboard' }) + dispatch('tagsView/delView', routeToDelete) + showMessage({ + message: language.t('login.unexpectedError'), + type: 'error' + }) + console.warn(`Dictionary Browser - Error ${error.code}: ${error.message}.`) + }) + }) + }, + changeBrowserAttribute({ commit, getters }, { + containerUuid, + browser, + attributeName, + attributeNameControl, + attributeValue + }) { + if (isEmptyValue(browser)) { + browser = getters.getBrowser(containerUuid) + } + commit('changeBrowserAttribute', { + browser, + attributeName, + attributeValue, + attributeNameControl + }) + } + }, + getters: { + getBrowser: (state) => (browserUuid) => { + return state.browser.find( + item => item.uuid === browserUuid + ) + } + } +} + +export default browser diff --git a/src/store/modules/ADempiere/calloutControl.js b/src/store/modules/ADempiere/calloutControl.js index 15f09c91..a3f0171f 100644 --- a/src/store/modules/ADempiere/calloutControl.js +++ b/src/store/modules/ADempiere/calloutControl.js @@ -1,5 +1,6 @@ import { runCallOutRequest } from '@/api/ADempiere/rule' import { showMessage } from '@/utils/ADempiere/notification' +import { isEmptyValue } from '@/utils/ADempiere/valueUtils' import language from '@/lang' const callOutControl = { @@ -19,7 +20,7 @@ const callOutControl = { * @param {String} valueType * @return {Promise} values */ - getCallout({ rootGetters, dispatch }, { + runCallout({ rootGetters, dispatch }, { parentUuid, containerUuid, callout, @@ -32,6 +33,10 @@ const callOutControl = { oldValue, valueType }) { + if (isEmptyValue(value) || isEmptyValue(callout)) { + return undefined + } + // Else return new Promise((resolve, reject) => { const window = rootGetters.getWindow(parentUuid) const attributesList = rootGetters.getParametersToServer({ diff --git a/src/store/modules/ADempiere/context.js b/src/store/modules/ADempiere/context.js deleted file mode 100644 index d058aff0..00000000 --- a/src/store/modules/ADempiere/context.js +++ /dev/null @@ -1,178 +0,0 @@ -import Vue from 'vue' -// Delete when get global context and account context -import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js' - -const context = { - state: { - context: {} - }, - mutations: { - /** - * Set context in state - * @param {string} payload.parentUuid - * @param {string} payload.containerUuid - * @param {string} payload.columnName - * @param {mixed} payload.value - */ - setContext(state, payload) { - let key = '' - if (payload.parentUuid) { - key += payload.parentUuid + '|' - - // set context for window - const keyParent = key + payload.columnName - Vue.set(state.context, keyParent, payload.value) - } - if (payload.containerUuid) { - key += payload.containerUuid + '|' - } - key += payload.columnName - // set property to object - Vue.set(state.context, key, payload.value) - }, - setInitialContext(state, objectContext) { - Object.keys(objectContext).forEach(key => { - Vue.set(state.context, key, objectContext[key]) - }) - }, - dictionaryResetCacheContext(state) { - state.context = {} - } - }, - actions: { - setContext({ commit }, objectValue) { - commit('setContext', objectValue) - }, - setMultipleContext({ commit }, valuesToSetter) { - valuesToSetter.forEach(itemToSetter => { - commit('setContext', itemToSetter) - }) - }, - setMultipleContextView({ commit }, { - parentUuid, - containerUuid, - values - }) { - Object.keys(values).forEach(key => { - commit('setContext', { - parentUuid, - containerUuid, - columnName: key, - value: values[key] - }) - }) - }, - setMultipleContextObject({ commit }, valuesToSetter) { - Object.keys(valuesToSetter).forEach(key => { - commit('setContext', { - columnName: key, - value: valuesToSetter[key] - }) - }) - }, - setMultipleContextMap({ commit }, valuesToSetter) { - return new Promise(resolve => { - valuesToSetter.forEach((value, key) => { - commit('setContext', { - columnName: key, - value: value - }) - }) - resolve() - }) - }, - setInitialContext({ commit }, otherContext = {}) { - commit('setInitialContext', otherContext) - } - }, - getters: { - /** - * @param {string} parentUuid - * @param {string} containerUuid - * @param {string} columnName - */ - getContext: (state) => ({ parentUuid, containerUuid, columnName }) => { - let key = '' - - if (parentUuid) { - key += parentUuid + '|' - - // context for window - const keyParent = key + columnName - const valueParent = state.context[keyParent] - if (!isEmptyValue(valueParent)) { - return valueParent - } - } - if (containerUuid) { - key += containerUuid + '|' - } - key += columnName - - return state.context[key] - }, - /** - * @param {string} parentUuid - * @param {string} containerUuid - * @returns {object} - */ - getContextView: (state) => ({ - parentUuid, - containerUuid - }) => { - // generate context with parent uuid or container uuid associated - const contextAllContainers = {} - Object.keys(state.context).forEach(key => { - if (key.includes(parentUuid) || key.includes(containerUuid)) { - contextAllContainers[key] = state.context[key] - } - }) - - // generate context only columnName - const contextContainer = {} - Object.keys(contextAllContainers).forEach(key => { - if (isEmptyValue(contextAllContainers[key])) { - return - } - let newKey - if (parentUuid) { - if (!key.includes(containerUuid)) { - newKey = key - .replace(`${parentUuid}|`, '') - .replace(`${containerUuid}|`, '') - // set window parent context - contextContainer[newKey] = contextAllContainers[key] - } - // next if is tab context - return - } - // set container context (smart browser, process/report) - newKey = key.replace(`${containerUuid}|`, '') - contextContainer[newKey] = contextAllContainers[key] - }) - - return contextContainer - }, - getContextAll: (state) => { - return state.context - }, - getContextClientId: (state) => { - return parseInt(state.context['#AD_Client_ID'], 10) - }, - getContextOrgId: (state) => { - return parseInt(state.context['#AD_Org_ID'], 10) - }, - // Using to read only in data tables - getContextIsActive: (state) => (parentUuid) => { - return state.context[`${parentUuid}|IsActive`] - }, - getContextProcessing: (state) => (parentUuid) => { - return state.context[`${parentUuid}|Processing`] - }, - getContextProcessed: (state) => (parentUuid) => { - return state.context[`${parentUuid}|Processed`] - } - } -} - -export default context diff --git a/src/store/modules/ADempiere/data.js b/src/store/modules/ADempiere/data.js index aca00384..4707c1c6 100644 --- a/src/store/modules/ADempiere/data.js +++ b/src/store/modules/ADempiere/data.js @@ -1,4 +1,3 @@ -import Vue from 'vue' import { getEntity, getEntitiesList } from '@/api/ADempiere/persistence' import { getDefaultValueFromServer, getContextInfoValueFromServer } from '@/api/ADempiere/values' import { getPrivateAccessFromServer, lockPrivateAccessFromServer, unlockPrivateAccessFromServer } from '@/api/ADempiere/private-access' @@ -70,9 +69,6 @@ const data = { addNewRow(state, payload) { payload.data = payload.data.unshift(payload.values) }, - addDisplayColumn(state, payload) { - Vue.set(payload.row, payload.columnName, payload.displayColumn) - }, setContextInfoField(state, payload) { state.contextInfoField.push(payload) }, @@ -202,7 +198,11 @@ const data = { if (fieldList.length) { fieldList // TODO: Evaluate if is field is read only and FieldSelect - .filter(itemField => itemField.componentPath === 'FieldSelect' || String(values[itemField.columnName]) === '[object Object]' || itemField.isSQLValue) + .filter(itemField => { + return itemField.componentPath === 'FieldSelect' || + String(values[itemField.columnName]) === '[object Object]' || + itemField.isSQLValue + }) .map(async itemField => { const { columnName, componentPath } = itemField let valueGetDisplayColumn = values[columnName] @@ -210,7 +210,7 @@ const data = { if (String(values[columnName]) === '[object Object]') { if (componentPath === 'FieldSelect') { values[columnName] = ' ' - values[`DisplayColumn_${columnName}`] = ' ' + values[itemField.displayColumnName] = ' ' } else if (componentPath === 'FieldNumber') { values[columnName] = 0 } @@ -237,7 +237,9 @@ const data = { } } - if (!isEmptyValue(valueGetDisplayColumn) && String(valueGetDisplayColumn) === '[object Object]' && valueGetDisplayColumn.isSQL) { + if (!isEmptyValue(valueGetDisplayColumn) && + String(valueGetDisplayColumn) === '[object Object]' && + valueGetDisplayColumn.isSQL) { // get value from Query valueGetDisplayColumn = await dispatch('getValueBySQL', { parentUuid, @@ -265,7 +267,7 @@ const data = { const option = options.find(itemOption => itemOption.key === valueGetDisplayColumn) // if there is a lookup option, assign the display column with the label if (option) { - values[`DisplayColumn_${columnName}`] = option.label + values[itemField.displayColumnName] = option.label // if (isEmptyValue(option.label) && !itemField.isMandatory) { // values[columnName] = undefined // } @@ -279,7 +281,7 @@ const data = { columnName: 'Name' }) if (!isEmptyValue(nameParent)) { - values[`DisplayColumn_${columnName}`] = nameParent + values[itemField.displayColumnName] = nameParent return } } @@ -291,7 +293,7 @@ const data = { directQuery: itemField.reference.directQuery, value: valueGetDisplayColumn }) - values[`DisplayColumn_${columnName}`] = label + values[itemField.displayColumnName] = label }) } @@ -308,26 +310,6 @@ const data = { data: dataStore }) }, - /** - * Add or change display column in table of records - * @param {string} containerUuid - * @param {string} columnName - * @param {string} displayColumn - */ - addDisplayColumn({ commit, getters }, { - containerUuid, - columnName, - displayColumn - }) { - const dataStore = getters.getDataRecordsList(containerUuid) - const rowRecord = dataStore.find(itemData => itemData.isNew) - - commit('addDisplayColumn', { - row: rowRecord, - displayColumn, - columnName: `DisplayColumn_${columnName}` - }) - }, /** * Is load context in true when panel is set context * @param {string} containerUuid @@ -524,6 +506,7 @@ const data = { defaultValues = rootGetters.getParsedDefaultValues({ parentUuid, containerUuid, + formatToReturn: 'object', isGetServer: false }) } @@ -744,7 +727,7 @@ const data = { if (isSendCallout && !withOutColumnNames.includes(field.columnName) && !isEmptyValue(newValue) && !isEmptyValue(field.callout)) { withOutColumnNames.push(field.columnName) - dispatch('getCallout', { + dispatch('runCallout', { parentUuid, containerUuid, tableName: field.tableName, diff --git a/src/store/modules/ADempiere/event.js b/src/store/modules/ADempiere/event.js index 77025d6f..ff16cf34 100644 --- a/src/store/modules/ADempiere/event.js +++ b/src/store/modules/ADempiere/event.js @@ -23,9 +23,11 @@ export const ACTION_PERFORMED = 1 export const FOCUS_GAINED = 2 export const FOCUS_LOST = 3 + // Input actions export const KEY_PRESSED = 4 export const KEY_RELEASED = 5 + const event = { state: { fieldEvents: [], diff --git a/src/store/modules/ADempiere/fieldValue.js b/src/store/modules/ADempiere/fieldValue.js new file mode 100644 index 00000000..c0e38cdd --- /dev/null +++ b/src/store/modules/ADempiere/fieldValue.js @@ -0,0 +1,159 @@ +import Vue from 'vue' +import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js' +import { convertStringToBoolean } from '@/utils/ADempiere/valueFormat.js' + +const UUID_KEY = 'UUID' + +const value = { + state: { + field: {} + }, + mutations: { + resetStatevalue(state) { + state = { + field: {} + } + }, + updateValueOfField(state, payload) { + // Only Parent + if (payload.parentUuid) { + const keyParent = payload.parentUuid + '_' + payload.columnName + if (payload.value !== state.field[keyParent]) { + Vue.set(state.field, keyParent, payload.value) + } + } + // Only Container + if (payload.containerUuid) { + const keyContainer = payload.containerUuid + '_' + payload.columnName + if (payload.value !== state.field[keyContainer]) { + Vue.set(state.field, keyContainer, payload.value) + } + } + }, + updateValuesOfContainer(state, payload) { + payload.attributes.forEach(attribute => { + const { value, columnName } = attribute + + // Only Parent + if (payload.parentUuid) { + const keyParent = payload.parentUuid + '_' + columnName + if (value !== state.field[keyParent]) { + Vue.set(state.field, keyParent, value) + } + } + // Only Container + if (payload.containerUuid) { + const keyContainer = payload.containerUuid + '_' + columnName + if (value !== state.field[keyContainer]) { + Vue.set(state.field, keyContainer, value) + } + } + }) + } + }, + actions: { + updateValuesOfContainer({ commit }, { + parentUuid, + containerUuid, + attributes = [] + }) { + commit('updateValuesOfContainer', { + parentUuid, + containerUuid, + attributes + }) + } + }, + getters: { + getValueOfField: (state) => ({ containerUuid, columnName }) => { + return state.field[containerUuid + '_' + columnName] + }, + getValueOfContainer: (state) => ({ parentUuid, containerUuid, columnName }) => { + // get in tab level + let value = state.field[containerUuid + '_' + columnName] + if (isEmptyValue(value) && parentUuid) { + // get in window level + value = state.field[parentUuid + '_' + columnName] + } + return value + }, + /** + * Get values and column's name as key (without parent uuid or container + * uuid), from a view (container) + * @param {string} parentUuid + * @param {string} containerUuid + * @returns {object|array} + */ + getValuesView: (state) => ({ + parentUuid, + containerUuid, + format = 'array' + }) => { + console.log(parentUuid, containerUuid) + // generate context with parent uuid or container uuid associated + const contextAllContainers = {} + Object.keys(state.field).forEach(key => { + if (key.includes(parentUuid) || key.includes(containerUuid)) { + contextAllContainers[key] = state.field[key] + } + }) + + // generate context only columnName + const objectValues = {} + const pairsValues = Object.keys(contextAllContainers).map(key => { + const value = contextAllContainers[key] + if (isEmptyValue(value)) { + return + } + let columnName + if (parentUuid) { + if (!key.includes(containerUuid)) { + columnName = key + .replace(`${parentUuid}_`, '') + .replace(`${containerUuid}_`, '') + // set window parent context + objectValues[columnName] = value + } + // next if is tab context + return { + columnName, + value + } + } + // set container context (smart browser, process/report, form) + columnName = key.replace(`${containerUuid}_`, '') + objectValues[columnName] = value + return { + columnName, + value + } + }) + + if (format === 'array') { + return pairsValues + } + return objectValues + }, + getUuidOfContainer: (state) => (containerUuid) => { + return state.field[containerUuid + '_' + UUID_KEY] + }, + // Using to read only in data tables in Window + getContainerIsActive: (state) => (parentUuid) => { + const valueIsActive = state.field[`${parentUuid}_IsActive`] + + return convertStringToBoolean(valueIsActive) + }, + getContainerProcessing: (state) => (parentUuid) => { + const valueProcessing = state.field[`${parentUuid}_Processing`] + + return convertStringToBoolean(valueProcessing) + }, + getContainerProcessed: (state) => (parentUuid) => { + const valueProcessed = state.field[`${parentUuid}_Processed`] + + return convertStringToBoolean(valueProcessed) + } + } +} + +export default value diff --git a/src/store/modules/ADempiere/form.js b/src/store/modules/ADempiere/formDefinition.js similarity index 100% rename from src/store/modules/ADempiere/form.js rename to src/store/modules/ADempiere/formDefinition.js diff --git a/src/store/modules/ADempiere/languageControl.js b/src/store/modules/ADempiere/language.js similarity index 100% rename from src/store/modules/ADempiere/languageControl.js rename to src/store/modules/ADempiere/language.js diff --git a/src/store/modules/ADempiere/lookup.js b/src/store/modules/ADempiere/lookup.js index 4e09632c..3c6793f8 100644 --- a/src/store/modules/ADempiere/lookup.js +++ b/src/store/modules/ADempiere/lookup.js @@ -1,4 +1,4 @@ -import { getLookup, getLookupList } from '@/api/ADempiere/values' +import { requestLookup, requestLookupList } from '@/api/ADempiere/values.js' import { getToken as getSession } from '@/utils/auth' import { isEmptyValue } from '@/utils/ADempiere/valueUtils' import { parseContext } from '@/utils/ADempiere/contextUtils' @@ -55,7 +55,7 @@ const lookup = { }).value } - return getLookup({ + return requestLookup({ tableName, directQuery: parsedDirectQuery, value @@ -73,7 +73,7 @@ const lookup = { parsedDirectQuery: directQuery, tableName, sessionUuid: getSession(), - clientId: rootGetters.getContextClientId + clientId: rootGetters.getPreferenceClientId }) return option }) @@ -83,16 +83,22 @@ const lookup = { }, /** * Get display column's list from lookup - * @param {string} parentUuid - * @param {string} containerUuid - * @param {string} tableName - * @param {string} query + * @param {string} parentUuid + * @param {string} containerUuid + * @param {string} tableName + * @param {string} query + * @param {boolean} isAddBlankValue + * @param {mixed} blankValue + * @param {Array|} valuesList */ getLookupListFromServer({ commit, rootGetters }, { parentUuid, containerUuid, tableName, - query + query, + isAddBlankValue = false, + blankValue, + valuesList = [] }) { if (isEmptyValue(query)) { return @@ -106,28 +112,38 @@ const lookup = { isBooleanToString: true }).value } - return getLookupList({ + return requestLookupList({ tableName, - query: parsedQuery + query: parsedQuery, + valuesList }) .then(lookupListResponse => { const list = [] lookupListResponse.recordsList.forEach(itemLookup => { - const key = itemLookup.values.KeyColumn - if (![null, -1, undefined].includes(key)) { + const { + KeyColumn: key, + DisplayColumn: label + } = itemLookup.values + + if (!isEmptyValue(key)) { list.push({ - label: itemLookup.values.DisplayColumn, + label, key }) } }) - + if (isAddBlankValue) { + list.unshift({ + label: ' ', + key: blankValue + }) + } commit('addLoockupList', { list, tableName, parsedQuery, sessionUuid: getSession(), - clientId: rootGetters.getContextClientId + clientId: rootGetters.getPreferenceClientId }) return list }) @@ -200,7 +216,7 @@ const lookup = { return itemLookup.parsedDirectQuery === parsedDirectQuery && itemLookup.tableName === tableName && itemLookup.sessionUuid === getSession() && - itemLookup.clientId === rootGetters.getContextClientId && + itemLookup.clientId === rootGetters.getPreferenceClientId && itemLookup.value === value }) if (lookupItem) { @@ -227,7 +243,7 @@ const lookup = { return itemLookup.parsedQuery === parsedQuery && itemLookup.tableName === tableName && itemLookup.sessionUuid === getSession() && - itemLookup.clientId === rootGetters.getContextClientId + itemLookup.clientId === rootGetters.getPreferenceClientId }) if (lookupList) { return lookupList.list diff --git a/src/store/modules/ADempiere/panel.js b/src/store/modules/ADempiere/panel.js index 9590963f..728f1529 100644 --- a/src/store/modules/ADempiere/panel.js +++ b/src/store/modules/ADempiere/panel.js @@ -5,10 +5,11 @@ // - Window: Just need storage tab and fields // - Process & Report: Always save a panel and parameters // - Smart Browser: Can have a search panel, table panel and process panel -import { isEmptyValue, parsedValueComponent } from '@/utils/ADempiere/valueUtils' -import evaluator, { getContext, parseContext } from '@/utils/ADempiere/contextUtils' -import { showMessage } from '@/utils/ADempiere/notification' -import { assignedGroup, fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils' +import { isEmptyValue, parsedValueComponent } from '@/utils/ADempiere/valueUtils.js' +import { convertObjectToKeyValue } from '@/utils/ADempiere/valueFormat.js' +import evaluator, { getContext, parseContext, specialColumns } from '@/utils/ADempiere/contextUtils.js' +import { showMessage } from '@/utils/ADempiere/notification.js' +import { assignedGroup, fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils.js' import router from '@/router' import language from '@/lang' @@ -56,7 +57,7 @@ const panel = { }, actions: { addPanel({ commit, dispatch, getters }, params) { - const { panelType } = params + const { panelType, uuid: containerUuid } = params let keyColumn = '' let selectionColumn = [] let identifierColumns = [] @@ -88,7 +89,7 @@ const panel = { if (['browser', 'process', 'report', 'form', 'table'].includes(panelType) || (panelType === 'window' && params.isParentTab)) { dispatch('setContext', { parentUuid: params.parentUuid, - containerUuid: params.uuid, + containerUuid, columnName: itemField.columnName, value: itemField.value }) @@ -136,6 +137,15 @@ const panel = { params.isShowedTableOptionalColumns = false commit('addPanel', params) + + if (!['form', 'table'].includes(panelType)) { + dispatch('setDefaultValues', { + parentUuid: params.parentUuid, + containerUuid, + panelType + }) + } + return params }, /** @@ -303,7 +313,7 @@ const panel = { * @param {array} fieldList * TODO: Evaluate if it is necessary to parse the default values */ - resetPanelToNew({ commit, dispatch, getters }, { + setDefaultValues({ commit, dispatch, getters }, { parentUuid, containerUuid, panelType = 'window', @@ -315,543 +325,287 @@ const panel = { resolve() return } + + const oldRoute = router.app._route const defaultAttributes = getters.getParsedDefaultValues({ parentUuid, containerUuid, + isSOTrxMenu: oldRoute.meta.isSOTrx, fieldsList: panel.fieldList }) if (panelType === 'window' && isNewRecord) { // redirect to create new record - const oldRoute = router.app._route - router.push({ - name: oldRoute.name, - params: { - ...oldRoute.params - }, - query: { - ...oldRoute.query, - action: 'create-new' - } - }) + if (!(oldRoute.query && oldRoute.query.action === 'create-new')) { + router.push({ + name: oldRoute.name, + params: { + ...oldRoute.params + }, + query: { + ...oldRoute.query, + action: 'create-new' + } + }) + } showMessage({ message: language.t('data.createNewRecord'), type: 'info' }) - panel.fieldList.forEach(fieldToBlank => { - if (isEmptyValue(fieldToBlank.parsedDefaultValue)) { - commit('changeFieldValueToNull', { - field: fieldToBlank, - value: undefined - }) - } - }) - - if (panel.isTabsChildren) { - // delete records tabs children when change record uuid - dispatch('deleteRecordContainer', { - viewUuid: parentUuid, - withOut: [containerUuid], - isNew: true + defaultAttributes.forEach(attribute => { + commit('addChangeToPersistenceQueue', { + ...attribute, + containerUuid }) - } + }) + // panel.fieldList.forEach(fieldToBlank => { + // if (isEmptyValue(fieldToBlank.parsedDefaultValue)) { + // commit('changeFieldValueToNull', { + // field: fieldToBlank, + // value: undefined + // }) + // } + // }) + + // if (panel.isTabsChildren) { + // // delete records tabs children when change record uuid + // dispatch('deleteRecordContainer', { + // viewUuid: parentUuid, + // withOut: [containerUuid], + // isNew: true + // }) + // } } - dispatch('notifyPanelChange', { + dispatch('updateValuesOfContainer', { parentUuid, containerUuid, - panelType, - fieldList: panel.fieldList, - newValues: defaultAttributes, - isSendToServer: false, - // if isNewRecord active callouts, if window is closed no send callout - isSendCallout: isNewRecord, - isPrivateAccess: false + attributes: defaultAttributes }) - .then(() => { - if (['process', 'report'].includes(panelType)) { - const fieldsUser = panel.fieldList.filter(itemField => { - return itemField.isShowedFromUserDefault || !isEmptyValue(itemField.value) - }).map(itemField => { - return itemField.columnName - }) + // .then(() => { + // if (['process', 'report'].includes(panelType)) { + // const fieldsUser = panel.fieldList.filter(itemField => { + // return itemField.isShowedFromUserDefault || !isEmptyValue(itemField.value) + // }).map(itemField => { + // return itemField.columnName + // }) - dispatch('changeFieldShowedFromUser', { - containerUuid, - fieldsUser, - groupField: '' - }) - } - }) + // dispatch('changeFieldShowedFromUser', { + // containerUuid, + // fieldsUser, + // groupField: '' + // }) + // } + // }) resolve(defaultAttributes) }) }, - /** - * Changed panel when receive or reset panel to new record - * @param {string} parentUuid - * @param {string} containerUuid - * @param {object} fieldList, field list of panel - * @param {object} newValues, values to set in panel - * @param {boolean} isSendToServer, indicate if changes send to server - * @param {boolean} isChangedAllValues, check if it changes all the values of the fields, if it does not exist, set an empty value - */ - notifyPanelChange({ dispatch, getters, rootGetters }, { + seekRecord({ dispatch, getters }, { parentUuid, containerUuid, - newValues = {}, - isSendToServer = true, - isShowedField = false, - panelType = 'window', - withOutColumnNames = [], - isSendCallout = true, - isAdvancedQuery = false, - isPrivateAccess = false, - fieldList = [], - isChangeFromCallout = false, - isChangeMultipleFields = true, - isChangedAllValues = false + recordUuid }) { - return new Promise(resolve => { - if (isEmptyValue(fieldList)) { - fieldList = getters.getFieldsListFromPanel(containerUuid, isAdvancedQuery) - } - let fieldsShowed = [] - const promisessList = [] - fieldList.map(async actionField => { - if (actionField.isShowedFromUser) { - fieldsShowed.push(actionField.columnName) - } - - // Evaluate with hasOwnProperty if exits this value - if (!Object.prototype.hasOwnProperty.call(newValues, actionField.columnName)) { - if (!isChangedAllValues || withOutColumnNames.includes(actionField.columnName)) { - // breaks if this value does not exist or ignore with out column names - return - } - // set empty value and continue - newValues[actionField.columnName] = undefined - } - - if (isChangeFromCallout && - actionField.componentPath === 'FieldSelect' && - !Object.prototype.hasOwnProperty.call(newValues, `DisplayColumn_${actionField.columnName}`)) { - let lookup = rootGetters.getLookupItem({ - parentUuid, - containerUuid, - directQuery: actionField.reference.directQuery, - tableName: actionField.reference.tableName, - value: newValues[actionField.columnName] - }) - - if (isEmptyValue(lookup) && !isEmptyValue(newValues[actionField.columnName])) { - lookup = await dispatch('getLookupItemFromServer', { - parentUuid, - containerUuid, - tableName: actionField.reference.tableName, - directQuery: actionField.reference.parsedDirectQuery, - value: newValues[actionField.columnName] - }) - } - if (!isEmptyValue(lookup)) { - newValues[`DisplayColumn_${actionField.columnName}`] = lookup.label - } - } - - promisessList.push(dispatch('notifyFieldChange', { - isSendToServer, - isSendCallout, - isAdvancedQuery, - panelType, - parentUuid, - containerUuid, - columnName: actionField.columnName, - displayColumn: newValues[`DisplayColumn_${actionField.columnName}`], - newValue: newValues[actionField.columnName], - valueTo: newValues[`${actionField.columnName}_To`], - fieldList, - field: actionField, - withOutColumnNames, - isChangedOldValue: true, // defines if set oldValue with newValue instead of current value - isChangeMultipleFields - })) + const recordRow = getters.getDataRecordAndSelection(containerUuid).record.find(record => record.UUID === recordUuid) + let attributes = [] + if (!isEmptyValue(recordRow)) { + attributes = convertObjectToKeyValue({ + object: recordRow }) - - Promise.all(promisessList) - .then(response => { - resolve() - const calloutsToExecute = [] - if (isSendCallout) { - response.forEach(item => { - if (item && !isEmptyValue(item.field.callout) && - !withOutColumnNames.includes(item.field.columnName)) { - withOutColumnNames.push(item.field.columnName) - calloutsToExecute.push({ - parentUuid, - containerUuid, - tableName: item.tableName, - columnName: item.field.columnName, - callout: item.field.callout, - value: item.newValue, - oldValue: item.field.oldValue, - withOutColumnNames - }) - } - }) - } - - calloutsToExecute.map(async executeCallout => { - await dispatch('getCallout', { - ...executeCallout - }) - }) - }) - - // show fields in query - if (isShowedField && !isEmptyValue(newValues)) { - // join column names without duplicating it - fieldsShowed = Array.from(new Set([ - ...fieldsShowed, - ...Object.keys(newValues) - ])) - - dispatch('changeFieldAttributesBoolean', { - containerUuid, - attribute: 'isShowedFromUser', - valueAttribute: true, - fieldsIncludes: fieldsShowed - }) - } - if (panelType === 'window') { - dispatch('setIsloadContext', { - containerUuid - }) - if (isPrivateAccess) { - const tableName = rootGetters.getTableNameFromTab(parentUuid, containerUuid) - // TODO: Add current id and new id to comparison - if (!isEmptyValue(newValues[`${tableName}_ID`])) { - dispatch('getPrivateAccessFromServer', { - tableName, - recordId: newValues[`${tableName}_ID`], - userUuid: rootGetters['user/getUserUuid'] - }) - } - } - } + } + // Change Value + dispatch('notifyPanelChange', { + parentUuid, + containerUuid, + attributes }) }, - /** - * TODO: Add fieldAttributes - * @param {string} parentUuid - * @param {string} containerUuid - * @param {string} panelType - * @param {boolean} isAdvancedQuery - * @param {string} columnName - * @param {mixin} newValue - * @param {mixin} valueTo - * @param {string} displayColumn, only used for lookup - * @param {boolean} isSendToServer - * @param {boolean} isSendCallout - * @param {boolean} isChangedOldValue - * @param {array} withOutColumnNames - */ - notifyFieldChange({ commit, dispatch, getters }, { + // Change all values of panel and dispatch actions for each field + notifyPanelChange({ commit }, { parentUuid, containerUuid, - panelType = 'window', - isAdvancedQuery = false, + attributes = [] + }) { + // Update field + commit('updateValuesOfContainer', { + parentUuid, + containerUuid, + attributes + }) + // return new Promise(resolve => { + // if (isEmptyValue(fieldList)) { + // fieldList = getters.getFieldsListFromPanel(containerUuid, isAdvancedQuery) + // } + // let fieldsShowed = [] + // // const promisessList = [] + // fieldList.map(async actionField => { + // if (actionField.isShowedFromUser) { + // fieldsShowed.push(actionField.columnName) + // } + // + // // Evaluate with hasOwnProperty if exits this value + // if (!Object.prototype.hasOwnProperty.call(newValues, actionField.columnName)) { + // if (!isChangedAllValues || withOutColumnNames.includes(actionField.columnName)) { + // // breaks if this value does not exist or ignore with out column names + // return + // } + // // set empty value and continue + // newValues[actionField.columnName] = undefined + // } + // + // if (isChangeFromCallout && + // actionField.componentPath === 'FieldSelect' && + // !Object.prototype.hasOwnProperty.call(newValues, actionField.displayColumnName)) { + // let lookup = rootGetters.getLookupItem({ + // parentUuid, + // containerUuid, + // directQuery: actionField.reference.directQuery, + // tableName: actionField.reference.tableName, + // value: newValues[actionField.columnName] + // }) + // + // if (isEmptyValue(lookup) && !isEmptyValue(newValues[actionField.columnName])) { + // lookup = await dispatch('getLookupItemFromServer', { + // parentUuid, + // containerUuid, + // tableName: actionField.reference.tableName, + // directQuery: actionField.reference.parsedDirectQuery, + // value: newValues[actionField.columnName] + // }) + // } + // if (!isEmptyValue(lookup)) { + // newValues[actionField.displayColumnName] = lookup.label + // } + // } + // // Update field + // commit('updateValueOfField', { + // parentUuid, + // containerUuid, + // columnName: actionField.columnName, + // value: newValues[actionField.columnName] + // }) + // }) + // // show fields in query + // if (isShowedField && !isEmptyValue(newValues)) { + // // join column names without duplicating it + // fieldsShowed = Array.from(new Set([ + // ...fieldsShowed, + // ...Object.keys(newValues) + // ])) + // + // dispatch('changeFieldAttributesBoolean', { + // containerUuid, + // attribute: 'isShowedFromUser', + // valueAttribute: true, + // fieldsIncludes: fieldsShowed + // }) + // } + // if (panelType === 'window') { + // dispatch('setIsloadContext', { + // containerUuid + // }) + // if (isPrivateAccess) { + // const tableName = rootGetters.getTableNameFromTab(parentUuid, containerUuid) + // // TODO: Add current id and new id to comparison + // if (!isEmptyValue(newValues[`${tableName}_ID`])) { + // dispatch('getPrivateAccessFromServer', { + // tableName, + // recordId: newValues[`${tableName}_ID`], + // userUuid: rootGetters['user/getUserUuid'] + // }) + // } + // } + // } + // }) + }, + /** + * Handle all trigger for a field: + * - Display Logic + * - Mandatory Logic + * - Read Only Logic + * - Action for Custom panel from type + */ + notifyFieldChange({ dispatch, getters }, { + containerUuid, columnName, - newValue, - valueTo, - displayColumn, - isSendToServer = true, - isSendCallout = true, - isChangedOldValue = false, - withOutColumnNames = [], - isChangeMultipleFields = false + field }) { // TODO: https://eslint.org/docs/rules/no-async-promise-executor // eslint-disable-next-line no-async-promise-executor return new Promise(async resolve => { - const panel = getters.getPanel(containerUuid, isAdvancedQuery) - const { fieldList: fieldsList, tableName } = panel // get field - const field = fieldsList.find(fieldItem => fieldItem.columnName === columnName) - - if (!(panelType === 'table' || isAdvancedQuery)) { - if (!['IN', 'NOT_IN'].includes(field.operator)) { - newValue = parsedValueComponent({ - fieldType: field.componentPath, - displayType: field.displayType, - value: newValue, - isIdentifier: field.columnName.includes('_ID') - }) - if (field.isRange) { - valueTo = parsedValueComponent({ - fieldType: field.componentPath, - displayType: field.displayType, - value: valueTo, - isIdentifier: field.columnName.includes('_ID') - }) - } - } - - // Call context management - dispatch('setContext', { - parentUuid, - containerUuid, - columnName, - value: newValue - }) - // request context info field - if ((!isEmptyValue(field.value) || !isEmptyValue(newValue)) && !isEmptyValue(field.contextInfo) && !isEmptyValue(field.contextInfo.sqlStatement)) { - let isSQL = false - let sqlStatement = field.contextInfo.sqlStatement - if (sqlStatement.includes('@')) { - if (sqlStatement.includes('@SQL=')) { - isSQL = true - } - sqlStatement = parseContext({ - parentUuid, - containerUuid, - columnName, - value: sqlStatement, - isSQL - }).value - if (isSQL && String(sqlStatement) === '[object Object]') { - sqlStatement = sqlStatement.query - } - } - const contextInfo = await dispatch('getContextInfoValueFromServer', { - parentUuid, - containerUuid, - contextInfoUuid: field.contextInfo.uuid, - columnName, - sqlStatement - }) - if (!isEmptyValue(contextInfo) && !isEmptyValue(contextInfo.messageText)) { - field.contextInfo.isActive = true - field.contextInfo.messageText.msgText = contextInfo.messageText - field.contextInfo.messageText.msgTip = contextInfo.messageTip - } - } - - // Change Dependents - dispatch('changeDependentFieldsList', { - parentUuid, - containerUuid, - dependentFieldsList: field.dependentFieldsList, - fieldsList, - isSendToServer - }) + if (!field) { + const { fieldsList } = getters.getPanel(containerUuid, false) + field = fieldsList.find(fieldItem => fieldItem.columnName === columnName) } - - // the field has not changed, then the action is broken - if (newValue === field.value && isEmptyValue(displayColumn) && field.isEvaluateValueChanges) { - resolve() - return - } - - commit('changeFieldValue', { - field, - newValue, - valueTo, - displayColumn, - isChangedOldValue + const value = getters.getValueOfField({ + containerUuid: field.containerUuid, + columnName: field.columnName }) + // if (!(panelType === 'table' || isAdvancedQuery)) { + // if (!['IN', 'NOT_IN'].includes(field.operator)) { + // value = parsedValueComponent({ + // componentPath: field.componentPath, + // columnName: field.columnName, + // displayType: field.displayType, + // value, + // isIdentifier: field.columnName.includes('_ID') + // }) + // if (field.isRange) { + // valueTo = parsedValueComponent({ + // componentPath: field.componentPath, + // columnName: field.columnName, + // displayType: field.displayType, + // value: valueTo, + // isIdentifier: field.columnName.includes('_ID') + // }) + // } + // } + // } resolve({ + tableName: field.tableName, field, - newValue, - valueTo, - displayColumn, - tableName + value }) - // request callouts - if (field.panelType === 'window' && isSendCallout && !isChangeMultipleFields) { - if (!withOutColumnNames.includes(field.columnName) && !isEmptyValue(newValue) && !isEmptyValue(field.callout)) { - withOutColumnNames.push(field.columnName) - dispatch('getCallout', { - parentUuid, - containerUuid, - tableName, - columnName: field.columnName, - callout: field.callout, - value: newValue, - oldValue: field.oldValue, - valueType: field.valueType, - withOutColumnNames - }) - } - } - - if (isSendToServer) { - if (panelType === 'table' || isAdvancedQuery) { - if (field.isShowedFromUser && (field.oldValue !== field.value || - ['NULL', 'NOT_NULL'].includes(field.operator) || - field.operator !== field.oldOperator)) { - // change action to advanced query on field value is changed in this panel - if (router.currentRoute.query.action !== 'advancedQuery') { - router.push({ - query: { - ...router.currentRoute.query, - action: 'advancedQuery' - } - }) - } - commit('changeField', { - field, - newField: { - ...field, - oldOperator: field.operator - } - }) - dispatch('getObjectListFromCriteria', { - parentUuid, - containerUuid, - tableName: panel.tableName, - query: panel.query, - whereClause: panel.whereClause, - conditionsList: getters.getParametersToServer({ - containerUuid, - isAdvancedQuery: true, - isEvaluateMandatory: false - }) - }) - .then(response => { - if (response && response.length) { - dispatch('notifyPanelChange', { - parentUuid, - containerUuid, - isAdvancedQuery: false, - newValues: response[0], - isSendToServer: false, - isSendCallout: true, - panelType: 'window' - }) - } - }) - .catch(error => { - console.warn(`Error getting Advanced Query (notifyFieldChange): ${error.message}. Code: ${error.code}.`) - }) - } - } else { - const fieldsEmpty = getters.getFieldListEmptyMandatory({ - containerUuid, - fieldsList - }) - - if (isEmptyValue(fieldsEmpty)) { - // TODO: refactory for it and change for a standard method - if (field.panelType === 'browser' && fieldIsDisplayed(field)) { - let isReadyForQuery = true - if (field.isSQLValue) { - let awaitForValuesToQuery = panel.awaitForValuesToQuery - awaitForValuesToQuery-- - dispatch('changeBrowserAttribute', { - containerUuid, - attributeName: 'awaitForValuesToQuery', - attributeValue: awaitForValuesToQuery - }) - if (awaitForValuesToQuery === 0) { - if (panel.isShowedCriteria) { - dispatch('changeBrowserAttribute', { - containerUuid, - attributeName: 'isShowedCriteria', - attributeValue: false - }) - } - } else if (awaitForValuesToQuery > 0) { - isReadyForQuery = false - } - } - if (isReadyForQuery && !field.dependentFieldsList.length) { - dispatch('getBrowserSearch', { - containerUuid, - isClearSelection: true - }) - } - } else if (field.panelType === 'window' && fieldIsDisplayed(field)) { - const uuid = getters.getUuid(containerUuid) - if (isEmptyValue(uuid)) { - dispatch('createNewEntity', { - parentUuid, - containerUuid - }) - .then(() => { - // change old value so that it is not send in the next update - commit('changeFieldValue', { - field, - newValue, - valueTo, - displayColumn, - isChangedOldValue: true - }) - }) - .catch(error => { - showMessage({ - message: error.message, - type: 'error' - }) - console.warn(`Create Entity Error ${error.code}: ${error.message}.`) - }) - } else { - dispatch('updateCurrentEntity', { - containerUuid, - recordUuid: uuid - }) - .then(response => { - // change old value so that it is not send in the next update - showMessage({ - message: language.t('notifications.updateFields') + field.name, - type: 'success' - }) - commit('changeFieldValue', { - field, - newValue, - valueTo, - displayColumn, - isChangedOldValue: true - }) - - // change value in table - dispatch('notifyRowTableChange', { - containerUuid, - row: response, - isEdit: false, - isParent: true - }) - }) - } - } - } else { - showMessage({ - message: language.t('notifications.mandatoryFieldMissing') + fieldsEmpty, - type: 'info' + // Run specific action + dispatch(field.panelType + 'ActionPerformed', { + containerUuid: field.containerUuid, + field, + value + }) + .then(response => { + if (response) { + dispatch('notifyPanelChange', { + containerUuid: field.containerUuid, + columnName: field.columnName, + attributes: response.values }) } - } - } + // Change Dependents + dispatch('changeDependentFieldsList', { + field + }) + }) + .catch(error => { + showMessage({ + message: error.message, + type: 'error' + }) + console.warn(`${field.panelType}ActionPerformed error: ${error.message}.`) + }) }) }, changeDependentFieldsList({ commit, dispatch, getters }, { - parentUuid, - containerUuid, - dependentFieldsList = [], - fieldsList = [], - isSendToServer + field }) { - if (isEmptyValue(dependentFieldsList)) { + if (isEmptyValue(field.dependentFieldsList)) { // breaks if there are no field dependencies return } - - if (!fieldsList.length) { - fieldsList = getters.getFieldsListFromPanel(containerUuid) - } - - const dependentsList = fieldsList.filter(fieldItem => { - return dependentFieldsList.includes(fieldItem.columnName) + // Get all fields + const dependentsList = getters.getFieldsListFromPanel(field.containerUuid).filter(fieldItem => { + return field.dependentFieldsList.includes(fieldItem.columnName) }) // Iterate for change logic @@ -861,8 +615,8 @@ const panel = { if (!isEmptyValue(fieldDependent.displayLogic)) { isDisplayedFromLogic = evaluator.evaluateLogic({ context: getContext, - parentUuid, - containerUuid, + parentUuid: field.parentUuid, + containerUuid: field.containerUuid, logic: fieldDependent.displayLogic }) } @@ -870,8 +624,8 @@ const panel = { if (!isEmptyValue(fieldDependent.mandatoryLogic)) { isMandatoryFromLogic = evaluator.evaluateLogic({ context: getContext, - parentUuid, - containerUuid, + parentUuid: field.parentUuid, + containerUuid: field.containerUuid, logic: fieldDependent.mandatoryLogic }) } @@ -879,8 +633,8 @@ const panel = { if (!isEmptyValue(fieldDependent.readOnlyLogic)) { isReadOnlyFromLogic = evaluator.evaluateLogic({ context: getContext, - parentUuid, - containerUuid, + parentUuid: field.parentUuid, + containerUuid: field.containerUuid, logic: fieldDependent.readOnlyLogic }) } @@ -889,34 +643,41 @@ const panel = { fieldDependent.defaultValue.includes('@') && !fieldDependent.defaultValue.includes('@SQL=')) { defaultValue = parseContext({ - parentUuid, - containerUuid, + parentUuid: field.parentUuid, + containerUuid: field.containerUuid, value: fieldDependent.defaultValue }).value } if (!isEmptyValue(fieldDependent.defaultValue) && fieldDependent.defaultValue.includes('@SQL=')) { defaultValue = parseContext({ - parentUuid, - containerUuid, + parentUuid: field.parentUuid, + containerUuid: field.containerUuid, isSQL: true, value: fieldDependent.defaultValue }).query if (defaultValue !== fieldDependent.parsedDefaultValue) { const newValue = await dispatch('getValueBySQL', { - parentUuid, - containerUuid, + parentUuid: field.parentUuid, + containerUuid: field.containerUuid, query: defaultValue }) - - dispatch('notifyFieldChange', { - parentUuid, - containerUuid, - isSendToServer, - panelType: fieldDependent.panelType, + // Update values for field + commit('updateValueOfField', { + parentUuid: field.parentUuid, + containerUuid: field.containerUuid, columnName: fieldDependent.columnName, - newValue + value: newValue }) + // + // dispatch('notifyFieldChange', { + // parentUuid, + // containerUuid, + // isSendToServer, + // panelType: fieldDependent.panelType, + // columnName: fieldDependent.columnName, + // newValue + // }) } } @@ -984,8 +745,8 @@ const panel = { newPanel[attributeName] = attributeValue } commit('changePanel', { - panel: panel, - newPanel: newPanel + panel, + newPanel }) }, /** @@ -1071,20 +832,18 @@ const panel = { // Obtain empty obligatory fields getFieldListEmptyMandatory: (state, getters) => ({ containerUuid, - fieldsList = [], - row + fieldsList }) => { - if (fieldsList.length <= 0) { + if (!fieldsList) { fieldsList = getters.getFieldsListFromPanel(containerUuid) } const fieldsEmpty = [] // all optionals (not mandatory) fields fieldsList.forEach(fieldItem => { - let value = fieldItem.value - // used when evaluate data in table - if (row) { - value = row[fieldItem.columnName] - } + const value = getters.getValueOfField({ + containerUuid, + columnName: fieldItem.columnName + }) if (isEmptyValue(value)) { const isMandatory = fieldItem.isMandatory || fieldItem.isMandatoryFromLogic if (fieldIsDisplayed(fieldItem) && isMandatory) { @@ -1092,7 +851,6 @@ const panel = { } } }) - return fieldsEmpty }, /** @@ -1114,7 +872,7 @@ const panel = { }, getUuid: (state, getters) => (containerUuid) => { const fieldUuid = getters.getColumnNamesAndValues({ - containerUuid: containerUuid, + containerUuid, isObjectReturn: true, isAddDisplayColumn: true }) @@ -1179,9 +937,10 @@ const panel = { // Add display columns if field has value if (fieldItem[propertyName] && fieldItem.displayColumn) { - attributesObject[`DisplayColumn_${fieldItem.columnName}`] = fieldItem.displayColumn + // TODO: Verify displayColumn attribute, or get dispay column to fieldValue store + attributesObject[fieldItem.displayColumnName] = fieldItem.displayColumn displayColumnsList.push({ - columnName: `DisplayColumn_${fieldItem.columnName}`, + columnName: fieldItem.displayColumnName, value: fieldItem.displayColumn }) } @@ -1216,56 +975,145 @@ const panel = { parentUuid, containerUuid, isGetServer = true, - fieldsList = [] + isSOTrxMenu, + fieldsList = [], + formatToReturn = 'array' }) => { if (isEmptyValue(fieldsList)) { fieldsList = getters.getFieldsListFromPanel(containerUuid) } + const attributesRangue = [] const attributesObject = {} - - fieldsList + let attributesList = fieldsList .map(fieldItem => { + const { columnName, defaultValue } = fieldItem let isSQL = false let valueToReturn = fieldItem.parsedDefaultValue - if (String(fieldItem.defaultValue).includes('@')) { - if (String(fieldItem.defaultValue).includes('@SQL=') && isGetServer) { + const isSpeciaColumn = specialColumns.includes(columnName) || specialColumns.includes(fieldItem.elementName) + + if (String(defaultValue).includes('@') || isSpeciaColumn) { + if (String(defaultValue).includes('@SQL=') && isGetServer) { isSQL = true } valueToReturn = parseContext({ - parentUuid: parentUuid, - containerUuid: containerUuid, - columnName: fieldItem.columnName, - value: fieldItem.defaultValue, + parentUuid, + containerUuid, + columnName, + value: defaultValue, + isSOTrxMenu, isSQL }) + if (isEmptyValue(valueToReturn.value) && + !isEmptyValue(fieldItem.elementName)) { + valueToReturn = parseContext({ + parentUuid, + containerUuid, + columnName: fieldItem.elementName, + value: defaultValue, + isSOTrxMenu, + isSQL + }) + } + if (typeof valueToReturn === 'object') { valueToReturn = { ...valueToReturn, - defaultValue: fieldItem.defaultValue + defaultValue } } } + if (String(valueToReturn) === '[object Object]') { + if (!valueToReturn.isSQL) { + valueToReturn = valueToReturn.value + } + } valueToReturn = parsedValueComponent({ - fieldType: fieldItem.componentPath, + componentPath: fieldItem.componentPath, + columnName, displayType: fieldItem.displayType, isMandatory: fieldItem.isMandatory, - value: String(valueToReturn) === '[object Object]' && valueToReturn.isSQL ? valueToReturn : String(valueToReturn) === '[object Object]' ? valueToReturn.value : valueToReturn, - isIdentifier: fieldItem.columnName.includes('_ID') + value: valueToReturn, + isIdentifier: columnName.includes('_ID') }) - attributesObject[fieldItem.columnName] = valueToReturn + attributesObject[columnName] = valueToReturn + + if (fieldItem.isRange && fieldItem.componentPath !== 'FieldNumber') { + const { columnNameTo, defaultValueTo } = fieldItem + let isSQLTo = false + let valueTo = fieldItem.parsedDefaultValueTo + + if (String(defaultValueTo).includes('@') || isSpeciaColumn) { + if (String(defaultValueTo).includes('@SQL=') && isGetServer) { + isSQLTo = true + } + valueTo = parseContext({ + parentUuid, + containerUuid, + columnName, + value: defaultValueTo, + isSOTrxMenu, + isSQL: isSQLTo + }) + if (isEmptyValue(valueTo.value) && + !isEmptyValue(fieldItem.elementNameTo)) { + valueTo = parseContext({ + parentUuid, + containerUuid, + columnName: fieldItem.elementNameTo, + value: defaultValueTo, + isSOTrxMenu, + isSQL: isSQLTo + }) + } + + if (typeof valueTo === 'object') { + valueTo = { + ...valueTo, + defaultValueTo + } + } + } + if (String(valueTo) === '[object Object]') { + if (!valueTo.isSQL) { + valueTo = valueTo.value + } + } + valueTo = parsedValueComponent({ + componentPath: fieldItem.componentPath, + columnName: columnNameTo, + displayType: fieldItem.displayType, + isMandatory: fieldItem.isMandatory, + value: valueTo, + isIdentifier: columnNameTo.includes('_ID') + }) + + attributesObject[columnNameTo] = valueTo + attributesRangue.push({ + columnName: columnNameTo, + value: valueTo, + valueType: fieldItem.valueType, + isSQL: isSQLTo + }) + } // add display column to default if (fieldItem.componentPath === 'FieldSelect' && fieldItem.value === valueToReturn) { - attributesObject[`DisplayColumn_${fieldItem.columnName}`] = fieldItem.displayColumn + // TODO: Verify displayColumn attribute, or get dispay column to fieldValue store + attributesObject[fieldItem.displayColumnName] = fieldItem.displayColumn } return { - columnName: fieldItem.columnName, + columnName, value: valueToReturn, + valueType: fieldItem.valueType, isSQL } }) + if (formatToReturn === 'array') { + attributesList = attributesList.concat(attributesRangue) + return attributesList + } return attributesObject }, getFieldsIsDisplayed: (state, getters) => (containerUuid) => { @@ -1345,17 +1193,15 @@ const panel = { * @param {Object} row * @param {Array} fieldList * @param {Array} withOutColumnNames - * @param {Boolean} isEvaluateDisplayed, default value is true * @param {Boolean} isEvaluateMandatory, default value is true * @param {Boolean} isAdvancedQuery, default value is false * @returns {Array} [{ columname: name key, value: value to send, operator }] */ - getParametersToServer: (state, getters) => ({ + getParametersToServer: (state, getters, rootState, rootGetters) => ({ containerUuid, row, fieldList = [], withOutColumnNames = [], - isEvaluateDisplayed = true, isEvaluateMandatory = true, isAdvancedQuery = false }) => { @@ -1367,8 +1213,10 @@ const panel = { // filter fields let parametersList = fieldList .filter(fieldItem => { + const { columnName } = fieldItem + // columns to exclude - if (withOutColumnNames.includes(fieldItem.columnName)) { + if (withOutColumnNames.includes(columnName)) { return false } @@ -1386,23 +1234,36 @@ const panel = { } // evaluate displayed fields - if (isEvaluateDisplayed) { - let isDisplayed = fieldIsDisplayed(fieldItem) && (fieldItem.isShowedFromUser || isMandatory) - if (isAdvancedQuery) { - isDisplayed = fieldItem.isShowedFromUser + let isDisplayed = fieldItem.isShowedFromUser + if (!isAdvancedQuery) { + // window, process, browser, form + isDisplayed = fieldIsDisplayed(fieldItem) && (fieldItem.isShowedFromUser || isMandatory) + } + + if (isDisplayed) { + // from table + if (row) { + if (!isEmptyValue(row[columnName])) { + return true + } + return false } - if (isDisplayed) { - if (row) { - if (!isEmptyValue(row[fieldItem.columnName])) { - return true - } - } else { - if (!isEmptyValue(fieldItem.value) || (isAdvancedQuery && - ['NULL', 'NOT_NULL'].includes(fieldItem.operator))) { - return true - } - } + // from field value + const value = rootGetters.getValueOfField({ + containerUuid, + columnName + }) + let valueTo + if (fieldItem.isRange && fieldItem.componentPath !== 'FieldNumber') { + valueTo = rootGetters.getValueOfField({ + containerUuid, + columnName: fieldItem.columnNameTo + }) + } + if (!isEmptyValue(value) || !isEmptyValue(valueTo) || (isAdvancedQuery && + ['NULL', 'NOT_NULL'].includes(fieldItem.operator))) { + return true } } @@ -1412,11 +1273,17 @@ const panel = { // conever parameters parametersList = parametersList .map(parameterItem => { - let value = parameterItem.value - let valueTo = parameterItem.valueTo + const { columnName, isRange } = parameterItem + let value + let valueTo if (row) { - value = row[parameterItem.columnName] - valueTo = row[`${parameterItem.columnName}_To`] + value = row[columnName] + valueTo = row[parameterItem.columnNameTo] + } else { + value = rootGetters.getValueOfField({ + containerUuid, + columnName: columnName + }) } let values = [] @@ -1425,11 +1292,12 @@ const panel = { values = value.map(itemValue => { const isMandatory = !isAdvancedQuery && (parameterItem.isMandatory || parameterItem.isMandatoryFromLogic) return parsedValueComponent({ - fieldType: parameterItem.componentPath, + componentPath: parameterItem.componentPath, + columnName, value: itemValue, displayType: parameterItem.displayType, isMandatory, - isIdentifier: parameterItem.columnName.includes('_ID') + isIdentifier: columnName.includes('_ID') }) }) } else { @@ -1445,11 +1313,16 @@ const panel = { } // only to fields type Time, Date and DateTime, and is range, with values // manage as Array = [value, valueTo] - if (parameterItem.isRange && parameterItem.componentPath !== 'FieldNumber') { + if (isRange && parameterItem.componentPath !== 'FieldNumber') { + valueTo = rootGetters.getValueOfField({ + containerUuid, + columnName: parameterItem.columnNameTo + }) operator = 'LESS_EQUAL' // operand to value is second position of array parametersRange.push({ - columnName: `${parameterItem.columnName}_To`, + columnName: parameterItem.columnNameTo, operator, + isRange, valueType: parameterItem.valueType, value: valueTo }) @@ -1457,10 +1330,10 @@ const panel = { } return { - columnName: parameterItem.columnName, + columnName, value, valueType: parameterItem.valueType, - isRange: parameterItem.isRange, + isRange, values, operator } diff --git a/src/store/modules/ADempiere/persistence.js b/src/store/modules/ADempiere/persistence.js new file mode 100644 index 00000000..e102e98d --- /dev/null +++ b/src/store/modules/ADempiere/persistence.js @@ -0,0 +1,80 @@ +import { createEntity, updateEntity } from '@/api/ADempiere/persistence.js' +import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js' + +const persistence = { + state: { + persistence: {} + }, + mutations: { + resetStatepersistence(state) { + state = { + persistence: {} + } + }, + addChangeToPersistenceQueue(state, { + containerUuid, + columnName, + valueType, + value + }) { + if (isEmptyValue(state.persistence[containerUuid])) { + state.persistence[containerUuid] = new Map() + } + // Set value + state.persistence[containerUuid].set(columnName, { + columnName, + valueType, + value + }) + } + }, + actions: { + flushPersistenceQueue({ getters }, { + containerUuid, + tableName, + recordUuid + }) { + return new Promise((resolve, reject) => { + let attributes = getters.getPersistenceAttributes(containerUuid) + if (attributes) { + if (recordUuid) { + // Update existing entity + updateEntity({ + tableName, + recordUuid, + attributes + }) + .then(response => resolve(response)) + .catch(error => reject(error)) + } else { + attributes = attributes.filter(itemAttribute => !isEmptyValue(itemAttribute.value)) + + // Create new entity + createEntity({ + tableName, + attributes + }) + .then(response => resolve(response)) + .catch(error => reject(error)) + } + } + }) + } + }, + getters: { + getPersistenceMap: (state) => (tableName) => { + return state.persistence[tableName] + }, + getPersistenceAttributes: (state) => (containerUuid) => { + const attributesMap = state.persistence[containerUuid] + if (!isEmptyValue(attributesMap)) { + return [ + ...attributesMap.values() + ] + } + return undefined + } + } +} + +export default persistence diff --git a/src/store/modules/ADempiere/preference.js b/src/store/modules/ADempiere/preference.js new file mode 100644 index 00000000..e5203e62 --- /dev/null +++ b/src/store/modules/ADempiere/preference.js @@ -0,0 +1,158 @@ +import Vue from 'vue' +// Delete when get global context and account context +import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js' + +const preference = { + state: { + preference: {} + }, + mutations: { + /** + * Set context in state + * @param {string} payload.parentUuid + * @param {string} payload.containerUuid + * @param {string} payload.columnName + * @param {mixed} payload.value + */ + setContext(state, payload) { + let key = '' + if (payload.parentUuid) { + key += payload.parentUuid + '|' + + // set context for window + const keyParent = key + payload.columnName + Vue.set(state.preference, keyParent, payload.value) + } + if (payload.containerUuid) { + key += payload.containerUuid + '|' + } + key += payload.columnName + // set property to object + Vue.set(state.preference, key, payload.value) + }, + setInitialContext(state, objectContext) { + Object.keys(objectContext).forEach(key => { + Vue.set(state.preference, key, objectContext[key]) + }) + }, + setMultiplePreference(state, preferenceToSet) { + if (!isEmptyValue(state.preference)) { + // join and overwrite old values + preferenceToSet = { + ...state.preference, + ...preferenceToSet + } + } + + state.preference = preferenceToSet + }, + dictionaryResetCacheContext(state) { + state.preference = {} + } + }, + actions: { + setContext({ commit }, objectValue) { + commit('setContext', objectValue) + }, + setMultiplePreference({ dispatch }, { + parentUuid, + containerUuid, + values + }) { + let actionToDispatch = 'setMultiplePreferenceObject' + if (Object.prototype.toString.call(values) === '[object Map]') { + actionToDispatch = 'setMultiplePreferenceMap' + } + return dispatch(actionToDispatch, { + parentUuid, + containerUuid, + values + }) + }, + setMultiplePreferenceObject({ commit }, { + parentUuid, + containerUuid, + values + }) { + return new Promise(resolve => { + if (!isEmptyValue(containerUuid) || !isEmptyValue(parentUuid)) { + Object.keys(values).forEach(key => { + commit('setContext', { + parentUuid, + containerUuid, + columnName: key, + value: values[key] + }) + }) + } else { + commit('setMultiplePreference', values) + } + + resolve() + }) + }, + setMultiplePreferenceMap({ commit }, { + parentUuid, + containerUuid, + values + }) { + return new Promise(resolve => { + if (!isEmptyValue(containerUuid) || !isEmptyValue(parentUuid)) { + values.forEach((value, key) => { + commit('setContext', { + parentUuid, + containerUuid, + columnName: key, + value + }) + }) + } else { + commit('setMultiplePreference', Object.fromEntries(values)) + } + resolve() + }) + } + }, + getters: { + /** + * @param {string} parentUuid + * @param {string} containerUuid + * @param {string} columnName + */ + getPreference: (state) => ({ + parentUuid, + containerUuid, + columnName + }) => { + let key = '' + + if (parentUuid) { + key += parentUuid + '|' + + // context for window + const keyParent = key + columnName + const valueParent = state.preference[keyParent] + if (!isEmptyValue(valueParent)) { + return valueParent + } + } + if (containerUuid) { + key += containerUuid + '|' + } + key += columnName + + return state.preference[key] + }, + getAllPreference: (state) => { + return state.preference + }, + getPreferenceClientId: (state) => { + return parseInt(state.preference['#AD_Client_ID'], 10) + }, + getPreferenceOrgId: (state) => { + return parseInt(state.preference['#AD_Org_ID'], 10) + } + } +} + +export default preference diff --git a/src/store/modules/ADempiere/process.js b/src/store/modules/ADempiere/process.js index 5e406b7d..767be657 100644 --- a/src/store/modules/ADempiere/process.js +++ b/src/store/modules/ADempiere/process.js @@ -1,112 +1,1013 @@ -import { getProcess as getProcessMetadata } from '@/api/ADempiere' -import { showMessage } from '@/utils/ADempiere' -import { generateProcess } from '@/utils/ADempiere/dictionaryUtils' +import { + runProcess, + requestListProcessesLogs +} from '@/api/ADempiere/process' +import { showNotification } from '@/utils/ADempiere/notification' +import { isEmptyValue } from '@/utils/ADempiere/valueUtils' import language from '@/lang' import router from '@/router' +import { getToken } from '@/utils/auth' -const process = { - state: { - process: [] - }, +const initStateProcessControl = { + inExecution: [], // process not response from server + isVisibleDialog: false, + reportObject: {}, + reportList: [], + metadata: {}, + process: [], // process to run finish + sessionProcess: [], + notificationProcess: [], + inRequestMetadata: [], + reportViewList: [], + totalResponse: 0, + totalRequest: 0, + totalSelection: 0, + errorSelection: 0, + successSelection: 0 +} + +const processControl = { + state: initStateProcessControl, mutations: { - addProcess(state, payload) { + // Add process in execution + addInExecution(state, payload) { + state.inExecution.push(payload) + }, + // Add process in notifation + addNotificationProcess(state, payload) { + state.notificationProcess.push(payload) + }, + // Delete process in execution afther some response from server + deleteInExecution(state, payload) { + state.inExecution = state.inExecution.filter(item => item.containerUuid !== payload.containerUuid) + }, + // Add process in request metadata from server + addInRequestMetadata(state, payload) { + state.inRequestMetadata.push(payload) + }, + // Delete process in request metadata + deleteInRequestMetadata(state, payload) { + state.inRequestMetadata = state.inRequestMetadata.filter(item => item !== payload) + }, + addStartedProcess(state, payload) { state.process.push(payload) }, - dictionaryResetCacheProcess(state) { - state.process = [] + resetStateProcessControl(state) { + state = initStateProcessControl + }, + /** + * + * @param {object} state + * @param {boolean} payload, true or false value to change displayed dialog + */ + setShowDialog(state, payload) { + state.isVisibleDialog = payload + }, + setMetadata(state, payload) { + state.metadata = payload + }, + setReportValues(state, payload) { + state.reportObject = payload + if (state.reportList.some(report => report.instanceUuid === payload.instanceUuid)) { + const reportIndex = state.reportList.findIndex(report => report.instanceUuid === payload.instanceUuid) + state.reportList.splice(reportIndex, 1, payload) + } else { + state.reportList.push(payload) + } + }, + setSessionProcess(state, payload) { + state.sessionProcess = payload.processList + }, + changeFormatReport(state, payload) { + state.reportFormat = payload + }, + setReportViewsList(state, payload) { + state.reportViewList.push(payload) + }, + setTotalResponse(state, payload) { + state.totalResponse = payload + }, + setTotalSelection(state, payload) { + state.totalSelection = payload + }, + setSuccessSelection(state, payload) { + state.successSelection = payload + }, + setErrorSelection(state, payload) { + state.errorSelection = payload + }, + setTotalRequest(state, payload) { + state.totalRequest = payload } }, actions: { - /** - * Get process/report metadata from server - * @param {string} containerUuid - * @param {number} processId - * @param {object} routeToDelete, route to close in tagView when fail - */ - getProcessFromServer({ commit, dispatch }, { + processActionPerformed({ commit }, { containerUuid, - processId, + field, + value + }) { + + }, + // Supported Actions for it + startProcess({ commit, state, dispatch, getters, rootGetters }, { + parentUuid, + containerUuid, + panelType, + action, + parametersList = [], + reportFormat, + isProcessTableSelection, + isActionDocument, + tableNameUuidSelection, + recordUuidSelection, + menuParentUuid, routeToDelete }) { - return new Promise(resolve => { - getProcessMetadata({ - uuid: containerUuid, - id: processId - }) - .then(async responseProcess => { - let printFormatsAvailable = [] - if (responseProcess.isReport) { - printFormatsAvailable = await dispatch('requestPrintFormats', { - processUuid: containerUuid + return new Promise((resolve, reject) => { + // TODO: Add support to evaluate parameters list to send + // const samePocessInExecution = getters.getInExecution(containerUuid) + // exists some call to executed process with container uuid + // if (samePocessInExecution && !isProcessTableSelection) { + // return reject({ + // error: 0, + // message: `In this process (${samePocessInExecution.name}) there is already an execution in progress.` + // }) + // } + + // additional attributes to send server, selection to browser, or table name and record id to window + let selection = [] + let allData = {} + let tab, tableName, recordId + if (panelType) { + if (panelType === 'browser') { + allData = getters.getDataRecordAndSelection(containerUuid) + selection = rootGetters.getSelectionToServer({ + containerUuid, + selection: allData.selection + }) + if (selection.length < 1) { + showNotification({ + title: language.t('data.selectionRequired'), + type: 'warning' + }) + return reject({ + error: 0, + message: `Required selection data record to run this process (${action.name})` }) } + } else if (panelType === 'window') { + const contextMenu = getters.getRecordUuidMenu + tab = rootGetters.getTab(parentUuid, containerUuid) + if (isProcessTableSelection) { + tableName = tableNameUuidSelection + recordId = recordUuidSelection + } else { + if (contextMenu.processTable) { + tableName = contextMenu.tableName + recordId = contextMenu.valueRecord + } else { + tableName = tab.tableName + const field = rootGetters.getFieldFromColumnName({ + containerUuid, + columnName: `${tableName}_ID` + }) + recordId = field.value + } + } + } + } + // get info metadata process + const processDefinition = !isEmptyValue(isActionDocument) ? action : rootGetters.getProcess(action.uuid) + let reportType = reportFormat - const { processDefinition, actions } = generateProcess({ - processToGenerate: { - ...responseProcess, - printFormatsAvailable + if (isEmptyValue(parametersList)) { + parametersList = rootGetters.getParametersToServer({ + containerUuid: processDefinition.uuid + }) + } + + const isSession = !isEmptyValue(getToken()) + let procesingMessage = { + close: () => false + } + if (isSession) { + procesingMessage = showNotification({ + title: language.t('notifications.processing'), + message: processDefinition.name, + summary: processDefinition.description, + type: 'info' + }) + } + const timeInitialized = (new Date()).getTime() + let processResult = { + // panel attributes from where it was executed + parentUuid, + containerUuid, + panelType, + lastRun: timeInitialized, + parametersList, + logs: [], + isError: false, + isProcessing: true, + summary: '', + resultTableName: '', + output: { + uuid: '', + name: '', + description: '', + fileName: '', + output: '', + outputStream: '', + reportType: '' + } + } + if (!isEmptyValue(isActionDocument)) { + processResult = { + ...processResult, + processUuid: action.uuid, + processId: action.id, + processName: 'Procesar Orden', + parameters: parametersList + } + } else { + // Run process on server and wait for it for notify + // uuid of process + processResult = { + ...processResult, + menuParentUuid, + processIdPath: routeToDelete.path, + printFormatUuid: action.printFormatUuid, + // process attributes + action: processDefinition.name, + name: processDefinition.name, + description: processDefinition.description, + instanceUuid: '', + processUuid: processDefinition.uuid, + processId: processDefinition.id, + processName: processDefinition.processName, + parameters: parametersList, + isReport: processDefinition.isReport + } + } + commit('addInExecution', processResult) + if (panelType === 'window') { + reportType = 'pdf' + } else if (panelType === 'browser') { + if (allData.record.length <= 100) { + // close view if is browser. + router.push({ path: '/dashboard' }) + dispatch('tagsView/delView', routeToDelete) + // delete data associate to browser + dispatch('deleteRecordContainer', { + viewUuid: containerUuid + }) + } + } else { + // close view if is process, report. + router.push({ path: '/dashboard' }) + dispatch('tagsView/delView', routeToDelete) + + // reset panel and set defalt isShowedFromUser + if (!processDefinition.isReport) { + dispatch('setDefaultValues', { + containerUuid, + panelType + }) + } + } + if (isProcessTableSelection) { + const windowSelectionProcess = getters.getProcessSelect + windowSelectionProcess.selection.forEach(selection => { + Object.assign(processResult, { + selection: selection.UUID, + record: selection[windowSelectionProcess.tableName] + }) + const countRequest = state.totalRequest + 1 + commit('setTotalRequest', countRequest) + if (!windowSelectionProcess.finish) { + runProcess({ + uuid: processDefinition.uuid, + id: processDefinition.id, + reportType, + parametersList, + selectionsList: selection, + tableName: windowSelectionProcess.tableName, + recordId: selection[windowSelectionProcess.tableName] + }) + .then(runProcessResponse => { + const { instanceUuid, output } = runProcessResponse + let logList = [] + if (runProcessResponse.logsList) { + logList = runProcessResponse.logsList + } + + let link = { + href: undefined, + download: undefined + } + if (processDefinition.isReport) { + const blob = new Blob( + [output.outputStream], + { type: output.mimeType } + ) + link = document.createElement('a') + link.href = window.URL.createObjectURL(blob) + link.download = output.fileName + if (reportType !== 'pdf' && reportType !== 'html') { + link.click() + } + + // Report views List to context menu + const reportViewList = { + name: language.t('views.reportView'), + type: 'summary', + action: '', + childs: [], + option: 'reportView' + } + reportViewList.childs = getters.getReportViewList(processResult.processUuid) + if (reportViewList && isEmptyValue(reportViewList.childs)) { + dispatch('requestReportViews', { + processUuid: processResult.processUuid, + instanceUuid, + processId: processDefinition.id, + tableName: output.tableName, + printFormatUuid: output.printFormatUuid, + reportViewUuid: output.reportViewUuid // TODO: Change to uuid + }) + .then(responseReportView => { + reportViewList.childs = responseReportView + if (reportViewList.childs.length) { + // Get contextMenu metadata and concat print report views with contextMenu actions + const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid) + contextMenuMetadata.actions.push(reportViewList) + } + }) + } + + // Print formats to context menu + const printFormatList = { + name: language.t('views.printFormat'), + type: 'summary', + action: '', + childs: [], + option: 'printFormat' + } + printFormatList.childs = rootGetters.getPrintFormatList(processResult.processUuid) + if (printFormatList && isEmptyValue(printFormatList.childs.length)) { + dispatch('requestPrintFormats', { + processUuid: processResult.processUuid, + instanceUuid, + processId: processDefinition.id, + tableName: output.tableName, + printFormatUuid: output.printFormatUuid, + reportViewUuid: output.reportViewUuid + }) + .then(printFormarResponse => { + printFormatList.childs = printFormarResponse + if (printFormatList.childs.length) { + // Get contextMenu metadata and concat print Format List with contextMenu actions + const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid) + contextMenuMetadata.actions.push(printFormatList) + } + }) + } + + // Drill Tables to context menu + const drillTablesList = { + name: language.t('views.drillTable'), + type: 'summary', + action: '', + childs: [], + option: 'drillTable' + } + if (!isEmptyValue(output.tableName)) { + drillTablesList.childs = rootGetters.getDrillTablesList(processResult.processUuid) + if (drillTablesList && isEmptyValue(drillTablesList.childs)) { + dispatch('requestDrillTables', { + processUuid: processResult.processUuid, + instanceUuid, + processId: processDefinition.id, + tableName: output.tableName, + printFormatUuid: output.printFormatUuid, + reportViewUuid: output.reportViewUuid + }) + .then(drillTablesResponse => { + drillTablesList.childs = drillTablesResponse + if (drillTablesList.childs.length) { + // Get contextMenu metadata and concat drill tables list with contextMenu actions + const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid) + contextMenuMetadata.actions.push(drillTablesList) + } + }) + } + } + } + // assign new attributes + Object.assign(processResult, { + ...runProcessResponse, + url: link.href, + download: link.download, + logs: logList, + output + }) + if (!isEmptyValue(processResult.output)) { + dispatch('setReportTypeToShareLink', processResult.output.reportType) + } + commit('addNotificationProcess', processResult) + resolve(processResult) + }) + .catch(error => { + Object.assign(processResult, { + isError: true, + message: error.message, + isProcessing: false + }) + console.warn(`Error running the process ${error}`) + reject(error) + }) + .finally(() => { + if (processResult.isError) { + const countError = state.errorSelection + 1 + commit('setErrorSelection', countError) + } else { + const countSuccess = state.successSelection + 1 + commit('setSuccessSelection', countSuccess) + } + const countResponse = state.totalResponse + 1 + commit('setTotalResponse', countResponse) + if (state.totalResponse === state.totalRequest) { + if (isSession) { + showNotification({ + title: language.t('notifications.succesful'), + message: language.t('notifications.totalProcess') + countResponse + language.t('notifications.error') + state.errorSelection + language.t('notifications.succesful') + state.successSelection + language.t('notifications.processExecuted'), + type: 'success' + }) + } + + commit('setTotalRequest', 0) + commit('setTotalResponse', 0) + commit('setSuccessSelection', 0) + commit('setErrorSelection', 0) + } + dispatch('setProcessSelect', { + selection: 0, + finish: true, + tableName: '' + }) + commit('addNotificationProcess', processResult) + commit('addStartedProcess', processResult) + commit('deleteInExecution', { + containerUuid + }) + }) + } + }) + } else { + runProcess({ + uuid: processDefinition.uuid, + id: processDefinition.id, + reportType, + parametersList, + selectionsList: selection, + tableName, + recordId + }) + .then(runProcessResponse => { + const { instanceUuid, output } = runProcessResponse + let logList = [] + if (!isEmptyValue(runProcessResponse.logsList)) { + logList = runProcessResponse.logsList + } + + let link = { + href: undefined, + download: undefined + } + if (runProcessResponse.isReport || processDefinition.isReport) { + const blob = new Blob( + [output.outputStream], + { type: output.mimeType } + ) + link = document.createElement('a') + link.href = window.URL.createObjectURL(blob) + link.download = output.fileName + if (reportType !== 'pdf' && reportType !== 'html') { + link.click() + } + const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid) + // Report views List to context menu + const reportViewList = { + name: language.t('views.reportView'), + type: 'summary', + action: '', + childs: [], + option: 'reportView' + } + reportViewList.childs = getters.getReportViewList(processResult.processUuid) + if (reportViewList && !reportViewList.childs.length) { + dispatch('requestReportViews', { + processUuid: processResult.processUuid, + instanceUuid, + processId: processDefinition.id, + tableName: output.tableName, + printFormatUuid: output.printFormatUuid, + reportViewUuid: output.reportViewUuid + }) + .then(responseReportView => { + reportViewList.childs = responseReportView + if (reportViewList.childs.length) { + // Get contextMenu metadata and concat print report views with contextMenu actions + contextMenuMetadata.actions.push(reportViewList) + } + }) + } + + // Print formats to context menu + const printFormatList = { + name: language.t('views.printFormat'), + type: 'summary', + action: '', + childs: [], + option: 'printFormat' + } + printFormatList.childs = rootGetters.getPrintFormatList(processResult.processUuid) + if (printFormatList && !printFormatList.childs.length) { + dispatch('requestPrintFormats', { + processUuid: processResult.processUuid, + instanceUuid, + processId: processDefinition.id, + tableName: output.tableName, + printFormatUuid: output.printFormatUuid, + reportViewUuid: output.reportViewUuid + }) + .then(printFormarResponse => { + printFormatList.childs = printFormarResponse + if (printFormatList.childs.length) { + // Get contextMenu metadata and concat print Format List with contextMenu actions + contextMenuMetadata.actions.push(printFormatList) + } + }) + } else { + const index = contextMenuMetadata.actions.findIndex(action => action.option === 'printFormat') + if (index !== -1) { + contextMenuMetadata.actions[index] = printFormatList + } + } + + // Drill Tables to context menu + const drillTablesList = { + name: language.t('views.drillTable'), + type: 'summary', + action: '', + childs: [], + option: 'drillTable' + } + if (!isEmptyValue(output.tableName)) { + drillTablesList.childs = rootGetters.getDrillTablesList(processResult.processUuid) + if (drillTablesList && isEmptyValue(drillTablesList.childs)) { + dispatch('requestDrillTables', { + processUuid: processResult.processUuid, + instanceUuid, + processId: processDefinition.id, + tableName: output.tableName, + printFormatUuid: output.printFormatUuid, + reportViewUuid: output.reportViewUuid + }) + .then(drillTablesResponse => { + drillTablesList.childs = drillTablesResponse + if (drillTablesList.childs.length) { + // Get contextMenu metadata and concat print Format List with contextMenu actions + contextMenuMetadata.actions.push(drillTablesList) + } + }) + } + } + } + // assign new attributes + Object.assign(processResult, { + ...runProcessResponse, + url: link.href, + download: link.download, + logs: logList, + output + }) + resolve(processResult) + if (!isEmptyValue(processResult.output)) { + dispatch('setReportTypeToShareLink', processResult.output.reportType) } }) + .catch(error => { + Object.assign(processResult, { + isError: true, + message: error.message, + isProcessing: false + }) + console.warn(`Error running the process ${error.message}. Code: ${error.code}.`) + reject(error) + }) + .finally(() => { + if (!processResult.isError) { + if (panelType === 'window') { + // TODO: Add conditional to indicate when update record + dispatch('updateRecordAfterRunProcess', { + parentUuid, + containerUuid, + tab + }) + } else if (panelType === 'browser') { + if (allData.record.length >= 100) { + dispatch('getBrowserSearch', { + containerUuid + }) + } + } + } - dispatch('addPanel', processDefinition) - commit('addProcess', processDefinition) - resolve(processDefinition) + commit('addNotificationProcess', processResult) + dispatch('finishProcess', { + processOutput: processResult, + procesingMessage, + routeToDelete + }) - // Add process menu - dispatch('setContextMenu', { - containerUuid, - actions + commit('deleteInExecution', { + containerUuid + }) + + dispatch('setProcessTable', { + valueRecord: 0, + tableName: '', + processTable: false + }) + dispatch('setProcessSelect', { + finish: true + }) }) - }) - .catch(error => { - router.push({ - path: '/dashboard' - }) - dispatch('tagsView/delView', routeToDelete) - showMessage({ - message: language.t('login.unexpectedError'), - type: 'error' - }) - console.warn(`Dictionary Process - Error ${error.message}.`) - }) + } }) }, - /** - * Add process associated in window or smart browser - * @param {object} processToGenerate - */ - addProcessAssociated({ commit, dispatch }, { - processToGenerate + // Supported to process selection + selectionProcess({ commit, state, dispatch, getters, rootGetters }, { + parentUuid, + containerUuid, + panelType, + action, + isProcessTableSelection, + parametersList = [], + menuParentUuid, + routeToDelete }) { - return new Promise(resolve => { - const { processDefinition, actions } = generateProcess({ - processToGenerate + // get info metadata process + const processDefinition = rootGetters.getProcess(action.uuid) + const reportType = 'pdf' + if (isEmptyValue(parametersList)) { + parametersList = rootGetters.getParametersToServer({ + containerUuid: processDefinition.uuid }) - - dispatch('addPanel', processDefinition) - commit('addProcess', processDefinition) - resolve(processDefinition) - - // Add process menu - dispatch('setContextMenu', { - containerUuid: processDefinition.uuid, - actions + } + const isSession = !isEmptyValue(getToken()) + if (isSession) { + showNotification({ + title: language.t('notifications.processing'), + message: processDefinition.name, + summary: processDefinition.description, + type: 'info' }) - }) + } + const timeInitialized = (new Date()).getTime() + // Run process on server and wait for it for notify + if (isProcessTableSelection) { + const windowSelectionProcess = getters.getProcessSelect + windowSelectionProcess.selection.forEach(selection => { + const processResult = { + // panel attributes from where it was executed + parentUuid, + containerUuid, + panelType, + menuParentUuid, + processIdPath: routeToDelete.path, + // process attributes + lastRun: timeInitialized, + action: processDefinition.name, + name: processDefinition.name, + description: processDefinition.description, + instanceUuid: '', + processUuid: processDefinition.uuid, + processId: processDefinition.id, + processName: processDefinition.processName, + parameters: parametersList, + isError: false, + isProcessing: true, + isReport: processDefinition.isReport, + summary: '', + resultTableName: '', + logs: [], + selection: selection.UUID, + record: selection[windowSelectionProcess.tableName], + output: { + uuid: '', + name: '', + description: '', + fileName: '', + output: '', + outputStream: '', + reportType: '' + } + } + const countRequest = state.totalRequest + 1 + commit('addInExecution', processResult) + commit('setTotalRequest', countRequest) + if (!windowSelectionProcess.finish) { + return runProcess({ + uuid: processDefinition.uuid, + id: processDefinition.id, + reportType, + parametersList, + selectionsList: selection, + tableName: windowSelectionProcess.tableName, + recordId: selection[windowSelectionProcess.tableName] + }) + .then(response => { + let output = { + uuid: '', + name: '', + description: '', + fileName: '', + mimeType: '', + output: '', + outputStream: '', + reportType: '' + } + if (isEmptyValue(response.output)) { + const responseOutput = response.output + output = { + uuid: responseOutput.uuid, + name: responseOutput.name, + description: responseOutput.description, + fileName: responseOutput.filename, + mimeType: responseOutput.mimeType, + output: responseOutput.output, + outputStream: responseOutput.outputstream, + reportType: responseOutput.reporttype + } + } + let logList = [] + if (response.getLogsList) { + logList = response.getLogsList.map(itemLog => { + return { + log: itemLog.log, + recordId: itemLog.recordid + } + }) + } + + // assign new attributes + Object.assign(processResult, { + instanceUuid: response.instanceUuid, + isError: response.isError, + isProcessing: response.isProcessing, + summary: response.summary, + ResultTableName: response.resulttablename, + lastRun: response.lastRun, + logs: logList, + output + }) + if (!isEmptyValue(processResult.output)) { + dispatch('setReportTypeToShareLink', processResult.output.reportType) + } + if (processResult.isError) { + const countError = state.errorSelection + 1 + commit('setErrorSelection', countError) + } else { + const countSuccess = state.successSelection + 1 + commit('setSuccessSelection', countSuccess) + } + const countResponse = state.totalResponse + 1 + commit('setTotalResponse', countResponse) + if (state.totalResponse === state.totalRequest) { + if (isSession) { + showNotification({ + title: language.t('notifications.succesful'), + message: language.t('notifications.totalProcess') + countResponse + language.t('notifications.error') + state.errorSelection + language.t('notifications.succesful') + state.successSelection + language.t('notifications.processExecuted'), + type: 'success' + }) + } + commit('setTotalRequest', 0) + commit('setTotalResponse', 0) + commit('setSuccessSelection', 0) + commit('setErrorSelection', 0) + } + dispatch('setProcessSelect', { + selection: 0, + finish: true, + tableName: '' + }) + commit('addNotificationProcess', processResult) + commit('addStartedProcess', processResult) + commit('deleteInExecution', { + containerUuid + }) + }) + .catch(error => { + Object.assign(processResult, { + isError: true, + message: error.message, + isProcessing: false + }) + console.warn(`Error running the process. Code ${error.code}: ${error.message}.`) + }) + } + }) + } + }, + /** + * TODO: Add date time in which the process/report was executed + */ + getSessionProcessFromServer({ commit, dispatch, getters, rootGetters }, parameters) { + // process Activity + const { pageToken, pageSize } = parameters + return requestListProcessesLogs({ pageToken, pageSize }) + .then(processActivityResponse => { + const responseList = processActivityResponse.processLogsList.map(processLogItem => { + const processMetadata = rootGetters.getProcess(processLogItem.uuid) + // if no exists metadata process in store and no request progess + if (processMetadata === undefined && getters.getInRequestMetadata(processLogItem.uuid) === undefined) { + commit('addInRequestMetadata', processLogItem.uuid) + dispatch('getProcessFromServer', { + containerUuid: processLogItem.uuid + }) + .finally(() => { + commit('deleteInRequestMetadata', processLogItem.uuid) + }) + } + const process = { + ...processLogItem, + processUuid: processLogItem.uuid + } + return process + }) + + const processResponseList = { + recordCount: processActivityResponse.recordCount, + processList: responseList, + nextPageToken: processActivityResponse.nextPageToken + } + commit('setSessionProcess', processResponseList) + return processResponseList + }) + .catch(error => { + showNotification({ + title: language.t('notifications.error'), + message: error.message, + type: 'error' + }) + console.warn(`Error getting process activity: ${error.message}. Code: ${error.code}.`) + }) + }, + /** + * Show modal dialog with process/report, tab (sequence) metadata + * @param {String} type of panel or panelType ('process', 'report', 'window') + * @param {Object} action + */ + setShowDialog({ state, commit, dispatch, rootGetters }, { + type, + action + }) { + const panels = ['process', 'report', 'window'] + if (action && (panels.includes(type) || panels.includes(action.panelType))) { + // show some process loaded in store + if (state.metadata && !isEmptyValue(state.metadata.containerUuid) && + state.metadata.containerUuid === action.containerUuid) { + commit('setShowDialog', true) + return + } + const panel = rootGetters.getPanel(action.containerUuid) + if (isEmptyValue(panel)) { + dispatch('getPanelAndFields', { + parentUuid: action.parentUuid, + containerUuid: isEmptyValue(action.uuid) ? action.containerUuid : action.uuid, + panelType: action.panelType + }) + .then(responsePanel => { + commit('setMetadata', responsePanel) + commit('setShowDialog', true) + }) + } else { + commit('setMetadata', panel) + commit('setShowDialog', true) + } + return + } + commit('setShowDialog', false) + }, + finishProcess({ commit }, { + processOutput, + routeToDelete, + procesingMessage + }) { + const processMessage = { + name: processOutput.processName, + title: language.t('notifications.succesful'), + message: language.t('notifications.processExecuted'), + type: 'success', + logs: processOutput.logs, + summary: processOutput.summary + } + const errorMessage = !isEmptyValue(processOutput.message) ? processOutput.message : language.t('notifications.error') + // TODO: Add isReport to type always 'success' + if (processOutput.isError || isEmptyValue(processOutput.processId) || isEmptyValue(processOutput.instanceUuid)) { + processMessage.title = language.t('notifications.error') + processMessage.message = errorMessage + processMessage.type = 'error' + processOutput.isError = true + } + if (processOutput.isReport && !processOutput.isError) { + // open report viewer with report response + let menuParentUuid = routeToDelete.params.menuParentUuid + if (isEmptyValue(menuParentUuid)) { + menuParentUuid = processOutput.menuParentUuid + } + + let tableName + if (processOutput.option && !isEmptyValue(processOutput.option)) { + if (processOutput.option === 'drillTable') { + tableName = processOutput.tableName + } + } + + router.push({ + name: 'Report Viewer', + params: { + processId: processOutput.processId, + instanceUuid: processOutput.instanceUuid, + fileName: isEmptyValue(processOutput.output.fileName) ? processOutput.fileName : processOutput.output.fileName, + menuParentUuid, + tableName + } + }) + } + const isSession = !isEmptyValue(getToken()) + if (isSession) { + showNotification(processMessage) + } + if (!isEmptyValue(procesingMessage)) { + procesingMessage.close() + } + + commit('addStartedProcess', processOutput) + commit('setReportValues', processOutput) + }, + changeFormatReport({ commit }, reportFormat) { + if (!isEmptyValue(reportFormat)) { + commit('changeFormatReport', reportFormat) + } } }, getters: { - getProcess: (state) => (processUuid) => { - return state.process.find( - item => item.uuid === processUuid - ) + /** + * Running processes that have not received a response from the server + * @param {string} containerUuid + */ + getInExecution: (state) => (containerUuid) => { + return state.inExecution.find(item => item.containerUuid === containerUuid) }, - getProcessById: (state) => (processId) => { - return state.process.find( - item => item.id === parseInt(processId) + /** + * Process for send to server, or send without response + */ + getAllInExecution: (state) => { + return state.inExecution + }, + /** + * Process send to server, with response from server + */ + getAllFinishProcess: (state) => { + return state.process + }, + getNotificationProcess: (state) => { + return state.notificationProcess + }, + /** + * Process receibed from server associated whith this session + */ + getAllSessionProcess: (state) => { + return state.sessionProcess + }, + /** + * Process request metadata from server filter form uuid process + */ + getInRequestMetadata: (state) => (containerUuid) => { + return state.inRequestMetadata.find(item => item === containerUuid) + }, + getProcessResult: (state) => { + return state.reportObject + }, + getCachedReport: (state) => (instanceUuid) => { + return state.reportList.find( + item => item.instanceUuid === instanceUuid ) } } } -export default process +export default processControl diff --git a/src/store/modules/ADempiere/processControl.js b/src/store/modules/ADempiere/processControl.js deleted file mode 100644 index 0eb14863..00000000 --- a/src/store/modules/ADempiere/processControl.js +++ /dev/null @@ -1,994 +0,0 @@ -import { - runProcess, - requestListProcessesLogs -} from '@/api/ADempiere/process' -import { showNotification } from '@/utils/ADempiere/notification' -import { isEmptyValue } from '@/utils/ADempiere/valueUtils' -import language from '@/lang' -import router from '@/router' -import { getToken } from '@/utils/auth' - -const initStateProcessControl = { - inExecution: [], // process not response from server - isVisibleDialog: false, - reportObject: {}, - reportList: [], - metadata: {}, - process: [], // process to run finish - sessionProcess: [], - notificationProcess: [], - inRequestMetadata: [], - reportViewList: [], - totalResponse: 0, - totalRequest: 0, - totalSelection: 0, - errorSelection: 0, - successSelection: 0 -} - -const processControl = { - state: initStateProcessControl, - mutations: { - // Add process in execution - addInExecution(state, payload) { - state.inExecution.push(payload) - }, - // Add process in notifation - addNotificationProcess(state, payload) { - state.notificationProcess.push(payload) - }, - // Delete process in execution afther some response from server - deleteInExecution(state, payload) { - state.inExecution = state.inExecution.filter(item => item.containerUuid !== payload.containerUuid) - }, - // Add process in request metadata from server - addInRequestMetadata(state, payload) { - state.inRequestMetadata.push(payload) - }, - // Delete process in request metadata - deleteInRequestMetadata(state, payload) { - state.inRequestMetadata = state.inRequestMetadata.filter(item => item !== payload) - }, - addStartedProcess(state, payload) { - state.process.push(payload) - }, - resetStateProcessControl(state) { - state = initStateProcessControl - }, - /** - * - * @param {object} state - * @param {boolean} payload, true or false value to change displayed dialog - */ - setShowDialog(state, payload) { - state.isVisibleDialog = payload - }, - setMetadata(state, payload) { - state.metadata = payload - }, - setReportValues(state, payload) { - state.reportObject = payload - if (state.reportList.some(report => report.instanceUuid === payload.instanceUuid)) { - const reportIndex = state.reportList.findIndex(report => report.instanceUuid === payload.instanceUuid) - state.reportList.splice(reportIndex, 1, payload) - } else { - state.reportList.push(payload) - } - }, - setSessionProcess(state, payload) { - state.sessionProcess = payload.processList - }, - changeFormatReport(state, payload) { - state.reportFormat = payload - }, - setReportViewsList(state, payload) { - state.reportViewList.push(payload) - }, - setTotalResponse(state, payload) { - state.totalResponse = payload - }, - setTotalSelection(state, payload) { - state.totalSelection = payload - }, - setSuccessSelection(state, payload) { - state.successSelection = payload - }, - setErrorSelection(state, payload) { - state.errorSelection = payload - }, - setTotalRequest(state, payload) { - state.totalRequest = payload - } - }, - actions: { - // Supported Actions for it - startProcess({ commit, state, dispatch, getters, rootGetters }, { - parentUuid, - containerUuid, - panelType, - action, - parametersList, - reportFormat, - isProcessTableSelection, - isActionDocument, - tableNameUuidSelection, - recordUuidSelection, - menuParentUuid, - routeToDelete - }) { - return new Promise((resolve, reject) => { - // TODO: Add support to evaluate parameters list to send - // const samePocessInExecution = getters.getInExecution(containerUuid) - // exists some call to executed process with container uuid - // if (samePocessInExecution && !isProcessTableSelection) { - // return reject({ - // error: 0, - // message: `In this process (${samePocessInExecution.name}) there is already an execution in progress.` - // }) - // } - - // additional attributes to send server, selection to browser, or table name and record id to window - let selection = [] - let allData = {} - let tab, tableName, recordId - if (panelType) { - if (panelType === 'browser') { - allData = getters.getDataRecordAndSelection(containerUuid) - selection = rootGetters.getSelectionToServer({ - containerUuid, - selection: allData.selection - }) - if (selection.length < 1) { - showNotification({ - title: language.t('data.selectionRequired'), - type: 'warning' - }) - return reject({ - error: 0, - message: `Required selection data record to run this process (${action.name})` - }) - } - } else if (panelType === 'window') { - const contextMenu = getters.getRecordUuidMenu - tab = rootGetters.getTab(parentUuid, containerUuid) - if (isProcessTableSelection) { - tableName = tableNameUuidSelection - recordId = recordUuidSelection - } else { - if (contextMenu.processTable) { - tableName = contextMenu.tableName - recordId = contextMenu.valueRecord - } else { - tableName = tab.tableName - const field = rootGetters.getFieldFromColumnName({ - containerUuid, - columnName: `${tableName}_ID` - }) - recordId = field.value - } - } - } - } - // get info metadata process - const processDefinition = !isEmptyValue(isActionDocument) ? action : rootGetters.getProcess(action.uuid) - let reportType = reportFormat - const finalParameters = rootGetters.getParametersToServer({ containerUuid: processDefinition.uuid }) - - const isSession = !isEmptyValue(getToken()) - let procesingMessage = { - close: () => false - } - if (isSession) { - procesingMessage = showNotification({ - title: language.t('notifications.processing'), - message: processDefinition.name, - summary: processDefinition.description, - type: 'info' - }) - } - const timeInitialized = (new Date()).getTime() - let processResult = { - // panel attributes from where it was executed - parentUuid, - containerUuid, - panelType, - lastRun: timeInitialized, - parametersList, - logs: [], - isError: false, - isProcessing: true, - summary: '', - resultTableName: '', - output: { - uuid: '', - name: '', - description: '', - fileName: '', - output: '', - outputStream: '', - reportType: '' - } - } - if (!isEmptyValue(isActionDocument)) { - processResult = { - ...processResult, - processUuid: action.uuid, - processId: action.id, - processName: 'Procesar Orden', - parameters: parametersList - } - } else { - // Run process on server and wait for it for notify - // uuid of process - processResult = { - ...processResult, - menuParentUuid, - processIdPath: routeToDelete.path, - printFormatUuid: action.printFormatUuid, - // process attributes - action: processDefinition.name, - name: processDefinition.name, - description: processDefinition.description, - instanceUuid: '', - processUuid: processDefinition.uuid, - processId: processDefinition.id, - processName: processDefinition.processName, - parameters: finalParameters, - isReport: processDefinition.isReport - } - } - commit('addInExecution', processResult) - if (panelType === 'window') { - reportType = 'pdf' - } else if (panelType === 'browser') { - if (allData.record.length <= 100) { - // close view if is browser. - router.push({ path: '/dashboard' }) - dispatch('tagsView/delView', routeToDelete) - // delete data associate to browser - dispatch('deleteRecordContainer', { - viewUuid: containerUuid - }) - } - } else { - // close view if is process, report. - router.push({ path: '/dashboard' }) - dispatch('tagsView/delView', routeToDelete) - - // reset panel and set defalt isShowedFromUser - if (!processDefinition.isReport) { - dispatch('resetPanelToNew', { - containerUuid, - panelType - }) - } - } - if (isProcessTableSelection) { - const windowSelectionProcess = getters.getProcessSelect - windowSelectionProcess.selection.forEach(selection => { - Object.assign(processResult, { - selection: selection.UUID, - record: selection[windowSelectionProcess.tableName] - }) - const countRequest = state.totalRequest + 1 - commit('setTotalRequest', countRequest) - if (!windowSelectionProcess.finish) { - runProcess({ - uuid: processDefinition.uuid, - id: processDefinition.id, - reportType, - parametersList: isEmptyValue(finalParameters) ? parametersList : finalParameters, - selectionsList: selection, - tableName: windowSelectionProcess.tableName, - recordId: selection[windowSelectionProcess.tableName] - }) - .then(runProcessResponse => { - const { instanceUuid, output } = runProcessResponse - let logList = [] - if (runProcessResponse.logsList) { - logList = runProcessResponse.logsList - } - - let link = { - href: undefined, - download: undefined - } - if (processDefinition.isReport) { - const blob = new Blob( - [output.outputStream], - { type: output.mimeType } - ) - link = document.createElement('a') - link.href = window.URL.createObjectURL(blob) - link.download = output.fileName - if (reportType !== 'pdf' && reportType !== 'html') { - link.click() - } - - // Report views List to context menu - const reportViewList = { - name: language.t('views.reportView'), - type: 'summary', - action: '', - childs: [], - option: 'reportView' - } - reportViewList.childs = getters.getReportViewList(processResult.processUuid) - if (reportViewList && isEmptyValue(reportViewList.childs)) { - dispatch('requestReportViews', { - processUuid: processResult.processUuid, - instanceUuid, - processId: processDefinition.id, - tableName: output.tableName, - printFormatUuid: output.printFormatUuid, - reportViewUuid: output.reportViewUuid // TODO: Change to uuid - }) - .then(responseReportView => { - reportViewList.childs = responseReportView - if (reportViewList.childs.length) { - // Get contextMenu metadata and concat print report views with contextMenu actions - const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid) - contextMenuMetadata.actions.push(reportViewList) - } - }) - } - - // Print formats to context menu - const printFormatList = { - name: language.t('views.printFormat'), - type: 'summary', - action: '', - childs: [], - option: 'printFormat' - } - printFormatList.childs = rootGetters.getPrintFormatList(processResult.processUuid) - if (printFormatList && isEmptyValue(printFormatList.childs.length)) { - dispatch('requestPrintFormats', { - processUuid: processResult.processUuid, - instanceUuid, - processId: processDefinition.id, - tableName: output.tableName, - printFormatUuid: output.printFormatUuid, - reportViewUuid: output.reportViewUuid - }) - .then(printFormarResponse => { - printFormatList.childs = printFormarResponse - if (printFormatList.childs.length) { - // Get contextMenu metadata and concat print Format List with contextMenu actions - const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid) - contextMenuMetadata.actions.push(printFormatList) - } - }) - } - - // Drill Tables to context menu - const drillTablesList = { - name: language.t('views.drillTable'), - type: 'summary', - action: '', - childs: [], - option: 'drillTable' - } - if (!isEmptyValue(output.tableName)) { - drillTablesList.childs = rootGetters.getDrillTablesList(processResult.processUuid) - if (drillTablesList && isEmptyValue(drillTablesList.childs)) { - dispatch('requestDrillTables', { - processUuid: processResult.processUuid, - instanceUuid, - processId: processDefinition.id, - tableName: output.tableName, - printFormatUuid: output.printFormatUuid, - reportViewUuid: output.reportViewUuid - }) - .then(drillTablesResponse => { - drillTablesList.childs = drillTablesResponse - if (drillTablesList.childs.length) { - // Get contextMenu metadata and concat drill tables list with contextMenu actions - const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid) - contextMenuMetadata.actions.push(drillTablesList) - } - }) - } - } - } - // assign new attributes - Object.assign(processResult, { - ...runProcessResponse, - url: link.href, - download: link.download, - logs: logList, - output - }) - if (!isEmptyValue(processResult.output)) { - dispatch('setReportTypeToShareLink', processResult.output.reportType) - } - commit('addNotificationProcess', processResult) - resolve(processResult) - }) - .catch(error => { - Object.assign(processResult, { - isError: true, - message: error.message, - isProcessing: false - }) - console.warn(`Error running the process ${error}`) - reject(error) - }) - .finally(() => { - if (processResult.isError) { - const countError = state.errorSelection + 1 - commit('setErrorSelection', countError) - } else { - const countSuccess = state.successSelection + 1 - commit('setSuccessSelection', countSuccess) - } - const countResponse = state.totalResponse + 1 - commit('setTotalResponse', countResponse) - if (state.totalResponse === state.totalRequest) { - if (isSession) { - showNotification({ - title: language.t('notifications.succesful'), - message: language.t('notifications.totalProcess') + countResponse + language.t('notifications.error') + state.errorSelection + language.t('notifications.succesful') + state.successSelection + language.t('notifications.processExecuted'), - type: 'success' - }) - } - - commit('setTotalRequest', 0) - commit('setTotalResponse', 0) - commit('setSuccessSelection', 0) - commit('setErrorSelection', 0) - } - dispatch('setProcessSelect', { - selection: 0, - finish: true, - tableName: '' - }) - commit('addNotificationProcess', processResult) - commit('addStartedProcess', processResult) - commit('deleteInExecution', { - containerUuid - }) - }) - } - }) - } else { - runProcess({ - uuid: processDefinition.uuid, - id: processDefinition.id, - reportType, - parametersList: isEmptyValue(finalParameters) ? parametersList : finalParameters, - selectionsList: selection, - tableName, - recordId - }) - .then(runProcessResponse => { - const { instanceUuid, output } = runProcessResponse - let logList = [] - if (!isEmptyValue(runProcessResponse.logsList)) { - logList = runProcessResponse.logsList - } - - let link = { - href: undefined, - download: undefined - } - if (runProcessResponse.isReport || processDefinition.isReport) { - const blob = new Blob( - [output.outputStream], - { type: output.mimeType } - ) - link = document.createElement('a') - link.href = window.URL.createObjectURL(blob) - link.download = output.fileName - if (reportType !== 'pdf' && reportType !== 'html') { - link.click() - } - const contextMenuMetadata = rootGetters.getContextMenu(processResult.processUuid) - // Report views List to context menu - const reportViewList = { - name: language.t('views.reportView'), - type: 'summary', - action: '', - childs: [], - option: 'reportView' - } - reportViewList.childs = getters.getReportViewList(processResult.processUuid) - if (reportViewList && !reportViewList.childs.length) { - dispatch('requestReportViews', { - processUuid: processResult.processUuid, - instanceUuid, - processId: processDefinition.id, - tableName: output.tableName, - printFormatUuid: output.printFormatUuid, - reportViewUuid: output.reportViewUuid - }) - .then(responseReportView => { - reportViewList.childs = responseReportView - if (reportViewList.childs.length) { - // Get contextMenu metadata and concat print report views with contextMenu actions - contextMenuMetadata.actions.push(reportViewList) - } - }) - } - - // Print formats to context menu - const printFormatList = { - name: language.t('views.printFormat'), - type: 'summary', - action: '', - childs: [], - option: 'printFormat' - } - printFormatList.childs = rootGetters.getPrintFormatList(processResult.processUuid) - if (printFormatList && !printFormatList.childs.length) { - dispatch('requestPrintFormats', { - processUuid: processResult.processUuid, - instanceUuid, - processId: processDefinition.id, - tableName: output.tableName, - printFormatUuid: output.printFormatUuid, - reportViewUuid: output.reportViewUuid - }) - .then(printFormarResponse => { - printFormatList.childs = printFormarResponse - if (printFormatList.childs.length) { - // Get contextMenu metadata and concat print Format List with contextMenu actions - contextMenuMetadata.actions.push(printFormatList) - } - }) - } else { - const index = contextMenuMetadata.actions.findIndex(action => action.option === 'printFormat') - if (index !== -1) { - contextMenuMetadata.actions[index] = printFormatList - } - } - - // Drill Tables to context menu - const drillTablesList = { - name: language.t('views.drillTable'), - type: 'summary', - action: '', - childs: [], - option: 'drillTable' - } - if (!isEmptyValue(output.tableName)) { - drillTablesList.childs = rootGetters.getDrillTablesList(processResult.processUuid) - if (drillTablesList && isEmptyValue(drillTablesList.childs)) { - dispatch('requestDrillTables', { - processUuid: processResult.processUuid, - instanceUuid, - processId: processDefinition.id, - tableName: output.tableName, - printFormatUuid: output.printFormatUuid, - reportViewUuid: output.reportViewUuid - }) - .then(drillTablesResponse => { - drillTablesList.childs = drillTablesResponse - if (drillTablesList.childs.length) { - // Get contextMenu metadata and concat print Format List with contextMenu actions - contextMenuMetadata.actions.push(drillTablesList) - } - }) - } - } - } - // assign new attributes - Object.assign(processResult, { - ...runProcessResponse, - url: link.href, - download: link.download, - logs: logList, - output - }) - resolve(processResult) - if (!isEmptyValue(processResult.output)) { - dispatch('setReportTypeToShareLink', processResult.output.reportType) - } - }) - .catch(error => { - Object.assign(processResult, { - isError: true, - message: error.message, - isProcessing: false - }) - console.warn(`Error running the process ${error.message}. Code: ${error.code}.`) - reject(error) - }) - .finally(() => { - if (!processResult.isError) { - if (panelType === 'window') { - // TODO: Add conditional to indicate when update record - dispatch('updateRecordAfterRunProcess', { - parentUuid, - containerUuid, - tab - }) - } else if (panelType === 'browser') { - if (allData.record.length >= 100) { - dispatch('getBrowserSearch', { - containerUuid - }) - } - } - } - - commit('addNotificationProcess', processResult) - dispatch('finishProcess', { - processOutput: processResult, - procesingMessage, - routeToDelete - }) - - commit('deleteInExecution', { - containerUuid - }) - - dispatch('setProcessTable', { - valueRecord: 0, - tableName: '', - processTable: false - }) - dispatch('setProcessSelect', { - finish: true - }) - }) - } - }) - }, - // Supported to process selection - selectionProcess({ commit, state, dispatch, getters, rootGetters }, { - parentUuid, - containerUuid, - panelType, - action, - isProcessTableSelection, - menuParentUuid, - routeToDelete - }) { - // get info metadata process - const processDefinition = rootGetters.getProcess(action.uuid) - const reportType = 'pdf' - const finalParameters = rootGetters.getParametersToServer({ containerUuid: processDefinition.uuid }) - const isSession = !isEmptyValue(getToken()) - if (isSession) { - showNotification({ - title: language.t('notifications.processing'), - message: processDefinition.name, - summary: processDefinition.description, - type: 'info' - }) - } - const timeInitialized = (new Date()).getTime() - // Run process on server and wait for it for notify - if (isProcessTableSelection) { - const windowSelectionProcess = getters.getProcessSelect - windowSelectionProcess.selection.forEach(selection => { - const processResult = { - // panel attributes from where it was executed - parentUuid, - containerUuid, - panelType, - menuParentUuid, - processIdPath: routeToDelete.path, - // process attributes - lastRun: timeInitialized, - action: processDefinition.name, - name: processDefinition.name, - description: processDefinition.description, - instanceUuid: '', - processUuid: processDefinition.uuid, - processId: processDefinition.id, - processName: processDefinition.processName, - parameters: finalParameters, - isError: false, - isProcessing: true, - isReport: processDefinition.isReport, - summary: '', - resultTableName: '', - logs: [], - selection: selection.UUID, - record: selection[windowSelectionProcess.tableName], - output: { - uuid: '', - name: '', - description: '', - fileName: '', - output: '', - outputStream: '', - reportType: '' - } - } - const countRequest = state.totalRequest + 1 - commit('addInExecution', processResult) - commit('setTotalRequest', countRequest) - if (!windowSelectionProcess.finish) { - return runProcess({ - uuid: processDefinition.uuid, - id: processDefinition.id, - reportType, - parametersList: finalParameters, - selectionsList: selection, - tableName: windowSelectionProcess.tableName, - recordId: selection[windowSelectionProcess.tableName] - }) - .then(response => { - let output = { - uuid: '', - name: '', - description: '', - fileName: '', - mimeType: '', - output: '', - outputStream: '', - reportType: '' - } - if (isEmptyValue(response.output)) { - const responseOutput = response.output - output = { - uuid: responseOutput.uuid, - name: responseOutput.name, - description: responseOutput.description, - fileName: responseOutput.filename, - mimeType: responseOutput.mimeType, - output: responseOutput.output, - outputStream: responseOutput.outputstream, - reportType: responseOutput.reporttype - } - } - let logList = [] - if (response.getLogsList) { - logList = response.getLogsList.map(itemLog => { - return { - log: itemLog.log, - recordId: itemLog.recordid - } - }) - } - - // assign new attributes - Object.assign(processResult, { - instanceUuid: response.instanceUuid, - isError: response.isError, - isProcessing: response.isProcessing, - summary: response.summary, - ResultTableName: response.resulttablename, - lastRun: response.lastRun, - logs: logList, - output - }) - dispatch('setReportTypeToShareLink', processResult.output.reportType) - if (processResult.isError) { - const countError = state.errorSelection + 1 - commit('setErrorSelection', countError) - } else { - const countSuccess = state.successSelection + 1 - commit('setSuccessSelection', countSuccess) - } - const countResponse = state.totalResponse + 1 - commit('setTotalResponse', countResponse) - if (state.totalResponse === state.totalRequest) { - if (isSession) { - showNotification({ - title: language.t('notifications.succesful'), - message: language.t('notifications.totalProcess') + countResponse + language.t('notifications.error') + state.errorSelection + language.t('notifications.succesful') + state.successSelection + language.t('notifications.processExecuted'), - type: 'success' - }) - } - commit('setTotalRequest', 0) - commit('setTotalResponse', 0) - commit('setSuccessSelection', 0) - commit('setErrorSelection', 0) - } - dispatch('setProcessSelect', { - selection: 0, - finish: true, - tableName: '' - }) - commit('addNotificationProcess', processResult) - commit('addStartedProcess', processResult) - commit('deleteInExecution', { - containerUuid - }) - }) - .catch(error => { - Object.assign(processResult, { - isError: true, - message: error.message, - isProcessing: false - }) - console.warn(`Error running the process. Code ${error.code}: ${error.message}.`) - }) - } - }) - } - }, - /** - * TODO: Add date time in which the process/report was executed - */ - getSessionProcessFromServer({ commit, dispatch, getters, rootGetters }, parameters) { - // process Activity - const { pageToken, pageSize } = parameters - return requestListProcessesLogs({ pageToken, pageSize }) - .then(processActivityResponse => { - const responseList = processActivityResponse.processLogsList.map(processLogItem => { - const processMetadata = rootGetters.getProcess(processLogItem.uuid) - // if no exists metadata process in store and no request progess - if (processMetadata === undefined && getters.getInRequestMetadata(processLogItem.uuid) === undefined) { - commit('addInRequestMetadata', processLogItem.uuid) - dispatch('getProcessFromServer', { - containerUuid: processLogItem.uuid - }) - .finally(() => { - commit('deleteInRequestMetadata', processLogItem.uuid) - }) - } - const process = { - ...processLogItem, - processUuid: processLogItem.uuid - } - return process - }) - - const processResponseList = { - recordCount: processActivityResponse.recordCount, - processList: responseList, - nextPageToken: processActivityResponse.nextPageToken - } - commit('setSessionProcess', processResponseList) - return processResponseList - }) - .catch(error => { - showNotification({ - title: language.t('notifications.error'), - message: error.message, - type: 'error' - }) - console.warn(`Error getting process activity: ${error.message}. Code: ${error.code}.`) - }) - }, - /** - * Show modal dialog with process/report, tab (sequence) metadata - * @param {String} type of panel or panelType ('process', 'report', 'window') - * @param {Object} action - */ - setShowDialog({ state, commit, dispatch, rootGetters }, { - type, - action - }) { - const panels = ['process', 'report', 'window'] - if (action && (panels.includes(type) || panels.includes(action.panelType))) { - // show some process loaded in store - if (state.metadata && !isEmptyValue(state.metadata.containerUuid) && - state.metadata.containerUuid === action.containerUuid) { - commit('setShowDialog', true) - return - } - const panel = rootGetters.getPanel(action.containerUuid) - if (panel === undefined) { - dispatch('getPanelAndFields', { - parentUuid: action.parentUuid, - containerUuid: isEmptyValue(action.uuid) ? action.containerUuid : action.uuid, - panelType: action.panelType - }) - .then(response => { - commit('setMetadata', response) - commit('setShowDialog', true) - }) - } else { - commit('setMetadata', panel) - commit('setShowDialog', true) - } - return - } - commit('setShowDialog', false) - }, - finishProcess({ commit }, { - processOutput, - routeToDelete, - procesingMessage - }) { - const processMessage = { - name: processOutput.processName, - title: language.t('notifications.succesful'), - message: language.t('notifications.processExecuted'), - type: 'success', - logs: processOutput.logs, - summary: processOutput.summary - } - const errorMessage = !isEmptyValue(processOutput.message) ? processOutput.message : language.t('notifications.error') - // TODO: Add isReport to type always 'success' - if (processOutput.isError || isEmptyValue(processOutput.processId) || isEmptyValue(processOutput.instanceUuid)) { - processMessage.title = language.t('notifications.error') - processMessage.message = errorMessage - processMessage.type = 'error' - processOutput.isError = true - } - if (processOutput.isReport && !processOutput.isError) { - // open report viewer with report response - let menuParentUuid = routeToDelete.params.menuParentUuid - if (isEmptyValue(menuParentUuid)) { - menuParentUuid = processOutput.menuParentUuid - } - - let tableName - if (processOutput.option && !isEmptyValue(processOutput.option)) { - if (processOutput.option === 'drillTable') { - tableName = processOutput.tableName - } - } - - router.push({ - name: 'Report Viewer', - params: { - processId: processOutput.processId, - instanceUuid: processOutput.instanceUuid, - fileName: isEmptyValue(processOutput.output.fileName) ? processOutput.fileName : processOutput.output.fileName, - menuParentUuid, - tableName - } - }) - } - const isSession = !isEmptyValue(getToken()) - if (isSession) { - showNotification(processMessage) - } - if (!isEmptyValue(procesingMessage)) { - procesingMessage.close() - } - - commit('addStartedProcess', processOutput) - commit('setReportValues', processOutput) - }, - changeFormatReport({ commit }, reportFormat) { - if (!isEmptyValue(reportFormat)) { - commit('changeFormatReport', reportFormat) - } - } - }, - getters: { - /** - * Running processes that have not received a response from the server - * @param {string} containerUuid - */ - getInExecution: (state) => (containerUuid) => { - return state.inExecution.find(item => item.containerUuid === containerUuid) - }, - /** - * Process for send to server, or send without response - */ - getAllInExecution: (state) => { - return state.inExecution - }, - /** - * Process send to server, with response from server - */ - getAllFinishProcess: (state) => { - return state.process - }, - getNotificationProcess: (state) => { - return state.notificationProcess - }, - /** - * Process receibed from server associated whith this session - */ - getAllSessionProcess: (state) => { - return state.sessionProcess - }, - /** - * Process request metadata from server filter form uuid process - */ - getInRequestMetadata: (state) => (containerUuid) => { - return state.inRequestMetadata.find(item => item === containerUuid) - }, - getProcessResult: (state) => { - return state.reportObject - }, - getCachedReport: (state) => (instanceUuid) => { - return state.reportList.find( - item => item.instanceUuid === instanceUuid - ) - } - } -} - -export default processControl diff --git a/src/store/modules/ADempiere/processDefinition.js b/src/store/modules/ADempiere/processDefinition.js new file mode 100644 index 00000000..556ea595 --- /dev/null +++ b/src/store/modules/ADempiere/processDefinition.js @@ -0,0 +1,112 @@ +import { getProcess as getProcessMetadata } from '@/api/ADempiere' +import { showMessage } from '@/utils/ADempiere' +import { generateProcess } from '@/utils/ADempiere/dictionaryUtils' +import language from '@/lang' +import router from '@/router' + +const process = { + state: { + process: [] + }, + mutations: { + addProcess(state, payload) { + state.process.push(payload) + }, + dictionaryResetCacheProcess(state) { + state.process = [] + } + }, + actions: { + /** + * Get Process/Report metadata from server + * @param {string} containerUuid + * @param {number} processId + * @param {object} routeToDelete, route to close in tagView when fail + */ + getProcessFromServer({ commit, dispatch }, { + containerUuid, + processId, + routeToDelete + }) { + return new Promise(resolve => { + getProcessMetadata({ + uuid: containerUuid, + id: processId + }) + .then(async responseProcess => { + let printFormatsAvailable = [] + if (responseProcess.isReport) { + printFormatsAvailable = await dispatch('requestPrintFormats', { + processUuid: containerUuid + }) + } + + const { processDefinition, actions } = generateProcess({ + processToGenerate: { + ...responseProcess, + printFormatsAvailable + } + }) + + dispatch('addPanel', processDefinition) + commit('addProcess', processDefinition) + resolve(processDefinition) + + // Add process menu + dispatch('setContextMenu', { + containerUuid, + actions + }) + }) + .catch(error => { + router.push({ + path: '/dashboard' + }) + dispatch('tagsView/delView', routeToDelete) + showMessage({ + message: language.t('login.unexpectedError'), + type: 'error' + }) + console.warn(`Dictionary Process - Error ${error.message}.`) + }) + }) + }, + /** + * Add process associated in window or smart browser + * @param {object} processToGenerate + */ + addProcessAssociated({ commit, dispatch }, { + processToGenerate + }) { + return new Promise(resolve => { + const { processDefinition, actions } = generateProcess({ + processToGenerate + }) + + dispatch('addPanel', processDefinition) + commit('addProcess', processDefinition) + resolve(processDefinition) + + // Add process menu + dispatch('setContextMenu', { + containerUuid: processDefinition.uuid, + actions + }) + }) + } + }, + getters: { + getProcess: (state) => (processUuid) => { + return state.process.find( + item => item.uuid === processUuid + ) + }, + getProcessById: (state) => (processId) => { + return state.process.find( + item => item.id === parseInt(processId) + ) + } + } +} + +export default process diff --git a/src/store/modules/ADempiere/reportControl.js b/src/store/modules/ADempiere/report.js similarity index 97% rename from src/store/modules/ADempiere/reportControl.js rename to src/store/modules/ADempiere/report.js index 67906aa4..c84d6e5a 100644 --- a/src/store/modules/ADempiere/reportControl.js +++ b/src/store/modules/ADempiere/report.js @@ -33,6 +33,13 @@ const reportControl = { } }, actions: { + reportActionPerformed({ commit }, { + containerUuid, + field, + value + }) { + + }, requestPrintFormats({ commit }, { processId, processUuid, @@ -147,7 +154,9 @@ const reportControl = { if (isEmptyValue(printFormatUuid)) { printFormatUuid = getters.getDefaultPrintFormat(processUuid).printFormatUuid } - const parametersList = rootGetters.getParametersToServer({ containerUuid: processUuid }) + const parametersList = rootGetters.getParametersToServer({ + containerUuid: processUuid + }) getReportOutput({ parametersList, printFormatUuid, diff --git a/src/store/modules/ADempiere/window.js b/src/store/modules/ADempiere/window.js index 917f7bbb..b7a95061 100644 --- a/src/store/modules/ADempiere/window.js +++ b/src/store/modules/ADempiere/window.js @@ -1,445 +1,1076 @@ import { - getWindow as getWindowMetadata, - getTab as getTabMetadata -} from '@/api/ADempiere/dictionary' -import { showMessage } from '@/utils/ADempiere/notification' + createEntity, + updateEntity, + deleteEntity, + rollbackEntity +} from '@/api/ADempiere/persistence' +import { getReferencesList } from '@/api/ADempiere/values' import { isEmptyValue } from '@/utils/ADempiere/valueUtils' +import { fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils' +import { parseContext } from '@/utils/ADempiere/contextUtils' +import { showMessage } from '@/utils/ADempiere/notification' import language from '@/lang' import router from '@/router' -import { generateField } from '@/utils/ADempiere/dictionaryUtils' -import { getFieldTemplate } from '@/utils/ADempiere/lookupFactory' -const initStateWindow = { - window: [], - windowIndex: 0 +const initStateWindowControl = { + inCreate: [], + references: [], + windowOldRoute: { + path: '', + fullPath: '', + query: {} + }, + dataLog: {}, // { containerUuid, recordId, tableName, eventType } + tabSequenceRecord: [], + totalResponse: 0, + totalRequest: 0 } -const window = { - state: initStateWindow, +const windowControl = { + state: initStateWindowControl, mutations: { - addWindow(state, payload) { - state.window.push(payload) - state.windowIndex++ + addInCreate(state, payload) { + state.inCreate.push(payload) }, - dictionaryResetCacheWindow(state) { - state = initStateWindow + deleteInCreate(state, payload) { + state.inCreate = state.inCreate.filter(item => item.containerUuid !== payload.containerUuid) }, - setCurrentTab(state, payload) { - payload.window.currentTab = payload.tab - payload.window.currentTabUuid = payload.tab.uuid + addReferencesList(state, payload) { + state.references.push(payload) }, - changeWindowAttribute(state, payload) { - let value = payload.attributeValue - if (payload.attributeNameControl) { - value = payload.window[payload.attributeNameControl] - } - payload.window[payload.attributeName] = value + setDataLog(state, payload) { + state.dataLog = payload }, - changeTabAttribute(state, payload) { - let value = payload.attributeValue - if (payload.attributeNameControl) { - value = payload.tab[payload.attributeNameControl] - } - payload.tab[payload.attributeName] = value + setWindowOldRoute(state, payload) { + state.windowOldRoute = payload + }, + setTabSequenceRecord(state, payload) { + state.tabSequenceRecord = payload + }, + setTotalResponse(state, payload) { + state.totalResponse = payload + }, + setTotalRequest(state, payload) { + state.totalRequest = payload + }, + resetStateWindowControl(state) { + state = initStateWindowControl } }, actions: { - getWindowFromServer({ commit, state, dispatch }, { - windowUuid, - windowId, - routeToDelete + tableActionPerformed({ dispatch, getters }, { + field, + value }) { - return getWindowMetadata({ - uuid: windowUuid, - id: windowId - }) - .then(responseWindow => { - const firstTabTableName = responseWindow.tabsList[0].tableName - const firstTabUuid = responseWindow.tabsList[0].uuid - const tabsListParent = [] - const tabsListChildren = [] - - const tabsSequence = [] - // TODO Add source tab on the server for tabs Translation and Sort - const tabs = responseWindow.tabsList.filter(itemTab => { - if (itemTab.isSortTab) { - // TODO: Add convert tab as process function - tabsSequence.push({ - uuid: itemTab.uuid, - id: itemTab.id, - parentUuid: windowUuid, - containerUuid: itemTab.uuid, - parentTabUuid: itemTab.parentTabUuid, - panelType: 'window', - type: 'sequence', - isSortTab: itemTab.isSortTab, - name: itemTab.name, - description: itemTab.description, - tableName: itemTab.tableName, - sortOrderColumnName: itemTab.sortOrderColumnName, // order column - sortYesNoColumnName: itemTab.sortYesNoColumnName // included column - }) - } - // TODO: Add support to isAdvancedTab, isTranslationTab and isHasTree - return !itemTab.isTranslationTab - }).map((tabItem, index, list) => { - // let tab = tabItem - const tab = { - ...tabItem, - containerUuid: tabItem.uuid, - parentUuid: windowUuid, - windowUuid, - tabGroup: tabItem.fieldGroup, - firstTabUuid, - // relations - isParentTab: Boolean(firstTabTableName === tabItem.tableName), - // app properties - isAssociatedTabSequence: false, // show modal with order tab - isShowedRecordNavigation: !(tabItem.isSingleRow), - isLoadFieldsList: false, - index - } - delete tab.processesList - - // action is dispatch used in vuex - let actions = [] - actions.push({ - // action to set default values and enable fields not isUpdateable - name: language.t('window.newRecord'), - processName: language.t('window.newRecord'), - type: 'dataAction', - action: 'resetPanelToNew', - uuidParent: windowUuid, - disabled: !tab.isInsertRecord || tab.isReadOnly - }, { - // action to delete record selected - name: language.t('window.deleteRecord'), - processName: language.t('window.deleteRecord'), - type: 'dataAction', - action: 'deleteEntity', - uuidParent: windowUuid, - disabled: tab.isReadOnly - }, { - // action to undo create, update, delete record - name: language.t('data.undo'), - processName: language.t('data.undo'), - type: 'dataAction', - action: 'undoModifyData', - uuidParent: windowUuid, - disabled: false - }, { - name: language.t('data.lockRecord'), - processName: language.t('data.lockRecord'), - type: 'dataAction', - action: 'lockRecord', - disabled: false, - hidden: true, - tableName: '', - recordId: null - }, { - name: language.t('data.unlockRecord'), - processName: language.t('data.unlockRecord'), - type: 'dataAction', - action: 'unlockRecord', - disabled: false, - hidden: true, - tableName: '', - recordId: null + // console.log({ + // field, + // value + // }) + }, + windowActionPerformed({ dispatch, getters }, { + field, + value + }) { + // get value from store + if (!value) { + value = getters.getValueOfField({ + containerUuid: field.containerUuid, + columnName: field.columnName + }) + } + return new Promise((resolve, reject) => { + // request callouts + dispatch('runCallout', { + parentUuid: field.parentUuid, + containerUuid: field.containerUuid, + tableName: field.tableName, + columnName: field.columnName, + callout: field.callout, + oldValue: field.oldValue, + valueType: field.valueType, + value + }) + .then(() => { + // Context Info + dispatch('reloadContextInfo', { + field }) - - if (tab.isSortTab) { - const tabParent = list.find(itemTab => itemTab.tableName === tab.tableName && !itemTab.isSortTab) - if (tabParent) { - tab.tabAssociatedUuid = tabParent.uuid // tab source uuid - tab.tabAssociatedName = tabParent.name // tab source name - } - } else { - // add tabs sequence associated as process in tab source - let orderTabs = tabsSequence.filter(itemTab => itemTab.tableName === tab.tableName) - if (orderTabs.length) { - orderTabs = orderTabs.map(itemTab => { - return { - ...itemTab, - // appication attributes - tabAssociatedUuid: tab.uuid, // tab source - tabAssociatedName: tab.name, // tab source - action: 'orderSequence', - panelType: 'window', - type: 'application' - } - }) - actions = actions.concat(orderTabs) - tab.isAssociatedTabSequence = true - tab.tabsOrder = orderTabs - } - } - - // get processess associated in tab - if (tabItem.processesList && tabItem.processesList.length) { - const processList = tabItem.processesList.map(processItem => { - // TODO: No list of parameters - // add process associated in vuex store - // dispatch('addProcessAssociated', { - // processToGenerate: processItem, - // containerUuidAssociated: tabItem.uuid - // }) - return { - id: processItem.id, - uuid: processItem.uuid, - name: processItem.name, - type: 'process', - panelType: 'process', - description: processItem.description, - help: processItem.help, - isReport: processItem.isReport, - isDirectPrint: processItem.isDirectPrint, - containerUuidAssociated: tabItem.uuid, - parentUuidAssociated: windowUuid, - panelTypeAssociated: 'window' + // Apply actions for server + dispatch('runServerAction', { + field, + value + }) + .then(response => resolve(response)) + .catch(error => reject(error)) + }) + }) + }, + runServerAction({ dispatch, getters, commit }, { + field, + value + }) { + return new Promise((resolve, reject) => { + // For change options + if (fieldIsDisplayed(field)) { + commit('addChangeToPersistenceQueue', { + ...field, + value + }) + const emptyFields = getters.getFieldListEmptyMandatory({ + containerUuid: field.containerUuid + }) + if (!isEmptyValue(emptyFields)) { + showMessage({ + message: language.t('notifications.mandatoryFieldMissing') + emptyFields, + type: 'info' + }) + } else { + const recordUuid = getters.getUuidOfContainer(field.containerUuid) + dispatch('flushPersistenceQueue', { + containerUuid: field.containerUuid, + tableName: field.tableName, + recordUuid + }) + .then(response => { + resolve(response) + if (isEmptyValue(recordUuid)) { + const oldRoute = router.app._route + router.push({ + name: oldRoute.name, + params: { + ...oldRoute.params + }, + query: { + ...oldRoute.query, + action: response.uuid + } + }) } }) - actions = actions.concat(processList) - } - // Add process menu - dispatch('setContextMenu', { - containerUuid: tab.uuid, - actions - }) - - if (tab.isParentTab) { - tabsListParent.push(tab) - return tab - } - if (!tab.isSortTab) { - tabsListChildren.push(tab) - } - return tab - }) - - const newWindow = { - ...responseWindow, - tabsList: tabs, - currentTab: tabsListParent[0], - tabsListParent, - tabsListChildren, - // app attributes - currentTabUuid: tabsListParent[0].uuid, - firstTab: tabsListParent[0], - firstTabUuid, - windowIndex: state.windowIndex + 1, - // App properties - isShowedTabsChildren: Boolean(tabsListChildren.length), - isShowedRecordNavigation: undefined, - isShowedAdvancedQuery: false + .catch(error => reject(error)) } - commit('addWindow', newWindow) - return newWindow - }) - .catch(error => { - router.push({ path: '/dashboard' }) - dispatch('tagsView/delView', routeToDelete) - showMessage({ - message: language.t('login.unexpectedError'), - type: 'error' - }) - console.warn(`Dictionary Window (State Window) - Error ${error.code}: ${error.message}.`) - }) + } + }) }, - getTabAndFieldFromServer({ dispatch, getters }, { + reloadContextInfo({ dispatch, getters }, { + field + }) { + // get value from store + const value = getters.getValueOfField({ + containerUuid: field.containerUuid, + columnName: field.columnName + }) + // request context info field + if (!isEmptyValue(value) && !isEmptyValue(field.contextInfo) && !isEmptyValue(field.contextInfo.sqlStatement)) { + let isSQL = false + let sqlStatement = field.contextInfo.sqlStatement + if (sqlStatement.includes('@')) { + if (sqlStatement.includes('@SQL=')) { + isSQL = true + } + sqlStatement = parseContext({ + parentUuid: field.parentUuid, + containerUuid: field.containerUuid, + columnName: field.columnName, + value: sqlStatement, + isSQL + }).value + if (isSQL && String(sqlStatement) === '[object Object]') { + sqlStatement = sqlStatement.query + } + } + const contextInfo = dispatch('getContextInfoValueFromServer', { + parentUuid: field.parentUuid, + containerUuid: field.containerUuid, + contextInfoUuid: field.contextInfo.uuid, + columnName: field.columnName, + sqlStatement + }) + if (!isEmptyValue(contextInfo) && !isEmptyValue(contextInfo.messageText)) { + field.contextInfo.isActive = true + field.contextInfo.messageText.msgText = contextInfo.messageText + field.contextInfo.messageText.msgTip = contextInfo.messageTip + } + } + }, + undoPanelToNew({ dispatch, rootGetters }, { containerUuid }) { + const oldAttributes = rootGetters.getColumnNamesAndValues({ + containerUuid, + propertyName: 'oldValue', + isObjectReturn: true, + isAddDisplayColumn: true + }) + dispatch('notifyPanelChange', { + containerUuid, + newValues: oldAttributes + }) + }, + // createNewEntity({ commit, dispatch, getters, rootGetters }, { + // parentUuid, + // containerUuid + // }) { + // return new Promise((resolve, reject) => { + // // exists some call to create new record with container uuid + // if (getters.getInCreate(containerUuid)) { + // return reject({ + // error: 0, + // message: `In this panel (${containerUuid}) is a create new record in progress` + // }) + // } + // + // const { tableName, fieldList } = rootGetters.getPanel(containerUuid) + // // delete key from attributes + // const attributesList = rootGetters.getColumnNamesAndValues({ + // containerUuid, + // propertyName: 'value', + // isEvaluateValues: true, + // isAddDisplayColumn: false + // }) + // console.log(attributesList) + // commit('addInCreate', { + // containerUuid, + // tableName, + // attributesList + // }) + // createEntity({ + // tableName, + // attributesList + // }) + // .then(createEntityResponse => { + // const newValues = createEntityResponse.values + // attributesList.forEach(element => { + // if (element.columnName.includes('DisplayColumn')) { + // newValues[element.columnName] = element.value + // } + // }) + // + // showMessage({ + // message: language.t('data.createRecordSuccessful'), + // type: 'success' + // }) + // + // // update fields with new values + // dispatch('notifyPanelChange', { + // parentUuid, + // containerUuid, + // newValues, + // isSendToServer: false + // }) + // dispatch('addNewRow', { + // parentUuid, + // containerUuid, + // isPanelValues: true, + // isEdit: false + // }) + // + // // set data log to undo action + // const fieldId = fieldList.find(itemField => itemField.isKey) + // dispatch('setDataLog', { + // containerUuid, + // tableName, + // recordId: fieldId.value, // TODO: Verify performance with tableName_ID + // recordUuid: newValues.UUID, + // eventType: 'INSERT' + // }) + // + // const oldRoute = router.app._route + // router.push({ + // name: oldRoute.name, + // params: { + // ...oldRoute.params + // }, + // query: { + // ...oldRoute.query, + // action: createEntityResponse.uuid + // } + // }) + // dispatch('tagsView/delView', oldRoute, true) + // + // resolve({ + // data: newValues, + // recordUuid: createEntityResponse.uuid, + // recordId: createEntityResponse.id, + // tableName: createEntityResponse.tableName + // }) + // }) + // .catch(error => { + // showMessage({ + // message: error.message, + // type: 'error' + // }) + // console.warn(`Create Entity error: ${error.message}.`) + // reject(error) + // }) + // .finally(() => { + // commit('deleteInCreate', { + // containerUuid, + // tableName, + // attributesList + // }) + // }) + // }) + // }, + createEntityFromTable({ commit, dispatch, getters, rootGetters }, { parentUuid, containerUuid, - tabId, - panelType = 'window', - panelMetadata, - isAdvancedQuery = false + row + }) { + // exists some call to create new record with container uuid + if (getters.getInCreate(containerUuid)) { + return { + error: 0, + message: `In this panel (${containerUuid}) is a create new record in progress.` + } + } + const { tableName, isParentTab } = rootGetters.getPanel(containerUuid) + + // TODO: Add support to Binary columns (BinaryData) + const columnsToDontSend = ['BinaryData', 'isEdit', 'isNew', 'isSendServer'] + + // TODO: Evaluate peformance without filter using delete(prop) before convert object to array + // attributes or fields + const fieldsList = getters.getFieldsListFromPanel(containerUuid) + const attributesList = [] + fieldsList.forEach(itemAttribute => { + if (columnsToDontSend.includes(itemAttribute.columnName) || itemAttribute.columnName.includes('DisplayColumn')) { + return false + } + if (isEmptyValue(row[itemAttribute.columnName])) { + return false + } + + attributesList.push({ + value: row[itemAttribute.columnName], + columnName: itemAttribute.columnName, + valueType: itemAttribute.valueType + }) + }) + + commit('addInCreate', { + containerUuid, + tableName, + attributesList + }) + + let isError = false + return createEntity({ + tableName, + attributesList + }) + .then(createEntityResponse => { + showMessage({ + message: language.t('data.createRecordSuccessful'), + type: 'success' + }) + if (isParentTab) { + // redirect to create new record + const oldRoute = router.app._route + router.push({ + name: oldRoute.name, + params: { + ...oldRoute.params + }, + query: { + ...oldRoute.query, + action: createEntityResponse.recordUuid + } + }) + } + return { + data: createEntityResponse.values, + ...createEntityResponse + } + }) + .catch(error => { + showMessage({ + message: error.message, + type: 'error' + }) + console.warn(`Create Entity Table Error ${error.code}: ${error.message}.`) + isError = true + }) + .finally(() => { + if (isError) { + dispatch('addNewRow', { + containerUuid, + row + }) + } else { + // refresh record list + dispatch('getDataListTab', { + parentUuid, + containerUuid + }) + .catch(error => { + console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) + }) + } + commit('deleteInCreate', { + containerUuid, + tableName, + attributesList + }) + }) + }, + // updateCurrentEntity({ dispatch, rootGetters }, { + // containerUuid, + // recordUuid = null + // }) { + // const panel = rootGetters.getPanel(containerUuid) + // if (!recordUuid) { + // recordUuid = rootGetters.getUuid(containerUuid) + // } + // + // // TODO: Add support to Binary columns (BinaryData) + // const columnsToDontSend = ['Account_Acct'] + // + // // attributes or fields + // let finalAttributes = rootGetters.getColumnNamesAndValues({ + // containerUuid: containerUuid, + // isEvaluatedChangedValue: true + // }) + // + // finalAttributes = finalAttributes.filter(itemAttribute => { + // if (columnsToDontSend.includes(itemAttribute.columnName) || itemAttribute.columnName.includes('DisplayColumn')) { + // return false + // } + // const field = panel.fieldList.find(itemField => itemField.columnName === itemAttribute.columnName) + // if (!field || !field.isUpdateable || !field.isDisplayed) { + // return false + // } + // return true + // }) + // return updateEntity({ + // tableName: panel.tableName, + // recordUuid, + // attributesList: finalAttributes + // }) + // .then(updateEntityResponse => { + // const newValues = updateEntityResponse.values + // // set data log to undo action + // // TODO: Verify performance with tableName_ID + // let recordId = updateEntityResponse.id + // if (isEmptyValue(recordId)) { + // recordId = newValues[`${panel.tableName}_ID`] + // } + // if (isEmptyValue(recordId)) { + // const fieldId = panel.fieldList.find(itemField => itemField.isKey) + // recordId = fieldId.value + // } + // + // if (isEmptyValue(recordUuid)) { + // recordUuid = updateEntityResponse.uuid + // } + // if (isEmptyValue(recordUuid)) { + // recordUuid = newValues.UUID + // } + // + // dispatch('setDataLog', { + // containerUuid, + // tableName: panel.tableName, + // recordId, + // recordUuid, + // eventType: 'UPDATE' + // }) + // if (rootGetters.getShowContainerInfo) { + // dispatch('listRecordLogs', { + // tableName: panel.tableName, + // recordId + // }) + // } + // return newValues + // }) + // .catch(error => { + // showMessage({ + // message: error.message, + // type: 'error' + // }) + // console.warn(`Update Entity Error ${error.code}: ${error.message}`) + // }) + // }, + // updateCurrentEntityFromTable({ rootGetters }, { + // containerUuid, + // row + // }) { + // const { tableName, fieldList } = rootGetters.getPanel(containerUuid) + // + // // TODO: Add support to Binary columns (BinaryData) + // const columnsToDontSend = ['BinaryData', 'isEdit', 'isNew', 'isSendServer'] + // + // // TODO: Evaluate peformance without filter using delete(prop) before convert object to array + // // attributes or fields + // let finalAttributes = convertObjectToKeyValue({ object: row }) + // finalAttributes = finalAttributes.filter(itemAttribute => { + // if (columnsToDontSend.includes(itemAttribute.columnName) || itemAttribute.columnName.includes('DisplayColumn')) { + // return false + // } + // const field = fieldList.find(itemField => itemField.columnName === itemAttribute.columnName) + // if (!field || !field.isUpdateable || !field.isDisplayed) { + // return false + // } + // return true + // }) + // + // return updateEntity({ + // tableName, + // recordUuid: row.UUID, + // attributesList: finalAttributes + // }) + // .then(response => { + // return response + // }) + // .catch(error => { + // showMessage({ + // message: error.message, + // type: 'error' + // }) + // console.warn(`Update Entity Table Error ${error.code}: ${error.message}.`) + // }) + // }, + /** + * Update record after run process associated with window + * @param {string} parentUuid + * @param {string} containerUuid + * @param {object} tab + */ + updateRecordAfterRunProcess({ dispatch, rootGetters }, { + parentUuid, + containerUuid, + tab + }) { + const recordUuid = rootGetters.getUuid(containerUuid) + // get new values + dispatch('getEntity', { + parentUuid, + containerUuid, + tableName: tab.tableName, + recordUuid + }) + .then(response => { + // update panel + if (tab.isParentTab) { + dispatch('notifyPanelChange', { + parentUuid, + containerUuid, + newValues: response, + isSendCallout: false, + isSendToServer: false + }) + } + // update row in table + dispatch('notifyRowTableChange', { + parentUuid, + containerUuid, + row: response, + isEdit: false + }) + }) + }, + deleteEntity({ dispatch, rootGetters }, { + parentUuid, + containerUuid, + recordUuid, + recordId, + row }) { return new Promise(resolve => { - getTabMetadata({ - uuid: containerUuid, - id: tabId - }) - .then(tabResponse => { - const additionalAttributes = { - parentUuid, - containerUuid, - isShowedFromUser: true, - panelType, - tableName: tabResponse.tableName, - // - isReadOnlyFromForm: false, - isAdvancedQuery, - isEvaluateValueChanges: !isAdvancedQuery - } + const panel = rootGetters.getPanel(containerUuid) + if (!isEmptyValue(row)) { + recordUuid = row.UUID + recordId = row[`${panel.tableName}_ID`] + } - let isWithUuidField = false // indicates it contains the uuid field - let fieldLinkColumnName - // Convert and add to app attributes - const fieldsList = tabResponse.fieldsList.map((fieldItem, index) => { - fieldItem = generateField({ - fieldToGenerate: fieldItem, - moreAttributes: { - ...additionalAttributes, - fieldListIndex: index + deleteEntity({ + tableName: panel.tableName, + recordUuid, + recordId + }) + .then(responseDeleteEntity => { + // refresh record list + dispatch('getDataListTab', { + parentUuid, + containerUuid + }) + .then(responseDataList => { + if (panel.isParentTab) { + // if response is void, go to new record + if (responseDataList.length <= 0) { + dispatch('setDefaultValues', { + parentUuid, + containerUuid, + panelType: 'window', + isNewRecord: true + }) + } else { + const oldRoute = router.app._route + // else display first record of table in panel + router.push({ + name: oldRoute.name, + params: { + ...oldRoute.params + }, + query: { + ...oldRoute.query, + action: responseDataList[0].UUID + } + }) + } } }) - - if (!isWithUuidField && fieldItem.columnName === 'UUID') { - isWithUuidField = true - } - - if (fieldItem.isParent) { - fieldLinkColumnName = fieldItem.columnName - } - - return fieldItem - }) - - let isTabsChildren = false - if (!isAdvancedQuery) { - const window = getters.getWindow(parentUuid) - isTabsChildren = Boolean(window.tabsListChildren.length) - } - - if (!isWithUuidField) { - const fieldUuid = getFieldTemplate({ - ...additionalAttributes, - isShowedFromUser: false, - name: 'UUID', - columnName: 'UUID', - componentPath: 'FieldText' + .catch(error => { + console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) }) - fieldsList.push(fieldUuid) - } - - if (isEmptyValue(panelMetadata)) { - panelMetadata = getters.getTab(parentUuid, containerUuid) - } - // Panel for save on store - const panel = { - ...panelMetadata, - isAdvancedQuery, - fieldLinkColumnName, - fieldList: fieldsList, - panelType, - // app attributes - isLoadFieldsList: true, - isShowedTotals: false, - isTabsChildren // to delete records assiciated - } - - dispatch('addPanel', panel) - resolve(panel) - - dispatch('changeTabAttribute', { - parentUuid, - containerUuid, - tab: panelMetadata, - attributeName: 'isLoadFieldsList', - attributeValue: true + showMessage({ + message: language.t('data.deleteRecordSuccessful'), + type: 'success' }) + + if (isEmptyValue(recordId)) { + // TODO: Verify performance with tableName_ID + const fieldId = panel.fieldList.find(itemField => itemField.isKey) + recordId = fieldId.value + } + // set data log to undo action + dispatch('setDataLog', { + containerUuid, + tableName: panel.tableName, + recordId, + recordUuid, + eventType: 'DELETE' + }) + + resolve(responseDeleteEntity) }) .catch(error => { showMessage({ - message: language.t('login.unexpectedError'), + message: language.t('data.deleteRecordError'), type: 'error' }) - console.warn(`Dictionary Tab (State Window) - Error ${error.code}: ${error.message}.`) + console.warn(`Delete Entity - Error ${error.message}, Code: ${error.code}.`) }) }) }, - setCurrentTab({ commit, getters }, { + /** + * Delete selection records in table + * @param {string} parentUuid + * @param {string} containerUuid + * @param {string} tableName + * @param {boolean} isParentTab + */ + deleteSelectionDataList({ dispatch, rootGetters }, { parentUuid, containerUuid, - window, - tab + tableName, + isParentTab }) { - if (isEmptyValue(window)) { - window = getters.getWindow(parentUuid) - } - if (isEmptyValue(tab)) { - tab = window.tabsList.find(itemTab => itemTab.uuid === containerUuid) + if (isEmptyValue(tableName) || isEmptyValue(isParentTab)) { + const tab = rootGetters.getTab(parentUuid, containerUuid) + tableName = tab.tableName + isParentTab = tab.isParentTab } + const allData = rootGetters.getDataRecordAndSelection(containerUuid) + let selectionLength = allData.selection.length - commit('setCurrentTab', { - window, - tab + allData.selection.forEach((record, index) => { + // validate if the registry row has no uuid before sending to the server + if (isEmptyValue(record.UUID)) { + selectionLength = selectionLength - 1 + console.warn(`This row does not contain a record with UUID`, record) + // refresh record list + dispatch('getDataListTab', { + parentUuid, + containerUuid + }) + .catch(error => { + console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) + }) + return + } + deleteEntity({ + tableName, + recordUuid: record.UUID + }) + .then(() => { + if (isParentTab) { + // redirect to create new record + const oldRoute = router.app._route + if (record.UUID === oldRoute.query.action) { + router.push({ + name: oldRoute.name, + params: { + ...oldRoute.params + }, + query: { + ...oldRoute.query, + action: 'create-new' + } + }) + // clear fields with default values + dispatch('setDefaultValues', { + parentUuid, + containerUuid + }) + // delete view with uuid record delete + dispatch('tagsView/delView', oldRoute, true) + } + } + + if ((index + 1) >= selectionLength) { + // refresh record list + dispatch('getDataListTab', { + parentUuid, + containerUuid + }) + .catch(error => { + console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) + }) + showMessage({ + message: language.t('data.deleteRecordSuccessful'), + type: 'success' + }) + } + }) }) }, - changeWindowAttribute({ commit, getters }, { - parentUuid, - window, - attributeName, - attributeNameControl, - attributeValue + undoModifyData({ getters }, { + containerUuid, + recordUuid }) { - if (isEmptyValue(window)) { - window = getters.getWindow(parentUuid) + return rollbackEntity(getters.getDataLog(containerUuid, recordUuid)) + .then(response => { + return response + }) + .catch(error => { + showMessage({ + message: error.message, + type: 'error' + }) + console.warn(`Rollback Entity error: ${error.message}. Code: ${error.code}.`) + }) + }, + setDataLog({ commit }, { + containerUuid, + tableName, + recordId, + recordUuid, + eventType + }) { + commit('setDataLog', { + containerUuid, + tableName, + recordId, + recordUuid, + eventType + }) + }, + /** + * Get data to table in tab + * @param {string} parentUuid, window to search record data + * @param {string} containerUuid, tab to search record data + * @param {string} recordUuid, uuid to search + * @param {boolean} isRefreshPanel, if main panel is updated with new response data + * @param {boolean} isLoadAllRecords, if main panel is updated with new response data + */ + getDataListTab({ dispatch, rootGetters }, { + parentUuid, + containerUuid, + recordUuid, + referenceWhereClause = '', + columnName, + value, + criteria, + isAddRecord = false, + isLoadAllRecords = false, + isRefreshPanel = false, + isReference = false, + isShowNotification = true + }) { + const tab = rootGetters.getTab(parentUuid, containerUuid) + + let parsedQuery = tab.query + if (!isEmptyValue(parsedQuery) && parsedQuery.includes('@')) { + parsedQuery = parseContext({ + parentUuid, + containerUuid, + value: tab.query, + isBooleanToString: true + }).value } - commit('changeWindowAttribute', { + let parsedWhereClause = tab.whereClause + if (!isEmptyValue(parsedWhereClause) && parsedWhereClause.includes('@')) { + parsedWhereClause = parseContext({ + parentUuid, + containerUuid, + value: tab.whereClause, + isBooleanToString: true + }).value + } + + if (isReference) { + if (!isEmptyValue(parsedWhereClause)) { + parsedWhereClause += ` AND ${referenceWhereClause}` + } else { + parsedWhereClause += referenceWhereClause + } + } + + if (!isEmptyValue(criteria)) { + if (!isEmptyValue(parsedWhereClause)) { + parsedWhereClause += ` AND ${criteria.whereClause}` + } else { + parsedWhereClause += criteria.whereClause + } + } + + const conditionsList = [] + // TODO: evaluate if overwrite values to conditions + if (!isLoadAllRecords && tab.isParentTab && !isEmptyValue(tab.tableName) && !isEmptyValue(value)) { + conditionsList.push({ + columnName, + value + }) + } + return dispatch('getObjectListFromCriteria', { parentUuid, - window, - attributeName, - attributeNameControl, - attributeValue + containerUuid, + tableName: tab.tableName, + query: parsedQuery, + whereClause: parsedWhereClause, + orderByClause: tab.orderByClause, + conditionsList, + isParentTab: tab.isParentTab, + isAddRecord, + isShowNotification + }) + .then(response => { + if (isRefreshPanel && !isEmptyValue(recordUuid) && recordUuid !== 'create-new') { + const newValues = response.find(itemData => itemData.UUID === recordUuid) + if (newValues) { + // update fields with values obtained from the server + dispatch('notifyPanelChange', { + parentUuid, + containerUuid, + newValues, + isSendCallout: false, + isSendToServer: false + }) + } else { + // this record is missing (Deleted or the query does not include it) + dispatch('setDefaultValues', { + parentUuid, + containerUuid + }) + } + } + return response + }) + .catch(error => { + return error + }) + .finally(() => { + const currentData = rootGetters.getDataRecordAndSelection(containerUuid) + const { originalNextPageToken, pageNumber, recordCount } = currentData + let nextPage = pageNumber + const isAdd = isAddRecord + if (originalNextPageToken && isAddRecord) { + const pageInToken = originalNextPageToken.substring(originalNextPageToken.length - 2) + if (pageInToken === '-1') { + isAddRecord = false + } + if (pageNumber === 1 && recordCount > 50) { + nextPage = nextPage + 1 + isAddRecord = true + } + } else { + isAddRecord = false + } + if (recordCount <= 50) { + isAddRecord = false + } + + if (isAddRecord) { + dispatch('setPageNumber', { + parentUuid, + containerUuid, + pageNumber: nextPage, + panelType: 'window', + isAddRecord, + isShowNotification: false + }) + } + if (isAdd && isAdd !== isAddRecord) { + if (tab.isSortTab) { + const record = rootGetters.getDataRecordsList(containerUuid) + const recordToTab = record + .map(itemRecord => { + return { + ...itemRecord + } + }) + .sort((itemA, itemB) => { + return itemA[tab.sortOrderColumnName] - itemB[tab.sortOrderColumnName] + }) + dispatch('setTabSequenceRecord', recordToTab) + } + } + }) + }, + /** + * Get references asociate to record + * @param {string} parentUuid as windowUuid + * @param {string} containerUuid + * @param {string} tableName + * @param {string} recordUuid + */ + getReferencesListFromServer({ commit, rootGetters }, { + parentUuid: windowUuid, + containerUuid, + tableName, + recordUuid + }) { + if (isEmptyValue(tableName)) { + tableName = rootGetters.getTab(windowUuid, containerUuid).tableName + } + return new Promise(resolve => { + getReferencesList({ + windowUuid, + tableName, + recordUuid + }) + .then(referenceResponse => { + const referencesList = referenceResponse.referencesList.map(item => { + return { + ...item, + recordUuid, + type: 'reference' + } + }) + const references = { + ...referenceResponse, + windowUuid, + recordUuid, + referencesList + } + commit('addReferencesList', references) + resolve(referenceResponse) + }) + .catch(error => { + console.warn(`References Load Error ${error.code}: ${error.message}.`) + }) }) }, - changeTabAttribute({ commit, getters }, { + setWindowOldRoute({ commit }, oldPath = { path: '', fullPath: '', query: {}}) { + commit('setWindowOldRoute', oldPath) + }, + setTabSequenceRecord({ commit }, record) { + commit('setTabSequenceRecord', record) + }, + /** + * Update records in tab sort + * @param {string} containerUuid + * @param {string} parentUuid + */ + updateSequence({ state, commit, dispatch, getters, rootGetters }, { parentUuid, - containerUuid, - tab, - attributeName, - attributeNameControl, - attributeValue + containerUuid }) { - if (isEmptyValue(tab)) { - tab = getters.getTab(parentUuid, containerUuid) - } - commit('changeTabAttribute', { - tab, - attributeName, - attributeValue, - attributeNameControl + const { tableName, sortOrderColumnName, sortYesNoColumnName, tabAssociatedUuid } = rootGetters.getTab(parentUuid, containerUuid) + const listSequenceToSet = getters.getTabSequenceRecord + const recordData = rootGetters.getDataRecordsList(containerUuid) + + // scrolls through the logs and checks if there is a change to be sent to server + recordData.forEach(itemData => { + const dataSequence = listSequenceToSet.find(item => item.UUID === itemData.UUID) + if (itemData[sortOrderColumnName] === dataSequence[sortOrderColumnName]) { + return + } + const valuesToSend = [{ + columnName: sortOrderColumnName, + value: dataSequence[sortOrderColumnName] + }] + + if (itemData[sortYesNoColumnName] !== dataSequence[sortYesNoColumnName]) { + valuesToSend.push({ + columnName: sortYesNoColumnName, + value: dataSequence[sortYesNoColumnName] + }) + } + + const countRequest = state.totalRequest + 1 + commit('setTotalRequest', countRequest) + + updateEntity({ + tableName, + recordUuid: itemData.UUID, + attributesList: valuesToSend + }) + .catch(error => { + showMessage({ + message: error.message, + type: 'error' + }) + console.warn(`Update Entity Table Error ${error.code}: ${error.message}`) + }) + .finally(() => { + const countResponse = state.totalResponse + 1 + commit('setTotalResponse', countResponse) + if (state.totalResponse === state.totalRequest) { + showMessage({ + message: language.t('notifications.updateSuccessfully'), + type: 'success' + }) + dispatch('setShowDialog', { + type: 'window', + action: undefined + }) + commit('setTotalRequest', 0) + commit('setTotalResponse', 0) + + dispatch('setRecordSelection', { + parentUuid, + containerUuid, + isLoaded: false + }) + dispatch('setTabSequenceRecord', []) + + // refresh record list in table source + dispatch('getDataListTab', { + parentUuid, + containerUuid: tabAssociatedUuid + }) + .catch(error => { + console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) + }) + } + }) }) } }, getters: { - getWindow: (state) => (windowUuid) => { - return state.window.find( - item => item.uuid === windowUuid - ) + getInCreate: (state) => (containerUuid) => { + return state.inCreate.find(item => item.containerUuid === containerUuid) }, - getIsShowedRecordNavigation: (state, getters) => (windowUuid) => { - const window = getters.getWindow(windowUuid) - if (window) { - return window.isShowedRecordNavigation - } - return window + getReferencesList: (state) => (windowUuid, recordUuid) => { + return state.references.find(item => item.windowUuid === windowUuid && item.recordUuid === recordUuid) }, - getTab: (state, getters) => (windowUuid, tabUuid) => { - const window = getters.getWindow(windowUuid) - if (window) { - return window.tabsList.find(tabItem => { - return tabItem.uuid === tabUuid - }) - } - return window + getReferencesInfo: (state, getters) => ({ windowUuid, recordUuid, referenceUuid }) => { + const references = getters.getReferencesList(windowUuid, recordUuid) + return references.referencesList.find(item => item.uuid === referenceUuid) }, - getCurrentTab: (state, getters) => (windowUuid) => { - const window = getters.getWindow(windowUuid) - if (window) { - return window.tabsList.find(tabItem => { - return tabItem.uuid === window.currentTabUuid - }) - } - return { - isInsertRecord: false - } + getTabSequenceRecord: (state) => { + return state.tabSequenceRecord }, - getTableNameFromTab: (state, getters) => (windowUuid, tabUuid) => { - return getters.getTab(windowUuid, tabUuid).tableName + getDataLog: (state) => (containerUuid, recordUuid) => { + const current = state.dataLog + if (current.containerUuid === containerUuid && + ((current.recordUuid === recordUuid) || + (current.eventType === 'DELETE' && recordUuid === 'create-new'))) { + return current + } + return undefined } } } -export default window +export default windowControl diff --git a/src/store/modules/ADempiere/windowControl.js b/src/store/modules/ADempiere/windowControl.js deleted file mode 100644 index 3a18bfd9..00000000 --- a/src/store/modules/ADempiere/windowControl.js +++ /dev/null @@ -1,935 +0,0 @@ -import { createEntity, updateEntity, deleteEntity, rollbackEntity } from '@/api/ADempiere/persistence' -import { getReferencesList } from '@/api/ADempiere/values' -import { convertObjectToArrayPairs, isEmptyValue } from '@/utils/ADempiere/valueUtils' -import { parseContext } from '@/utils/ADempiere/contextUtils' -import { showMessage } from '@/utils/ADempiere/notification' -import language from '@/lang' -import router from '@/router' - -const initStateWindowControl = { - inCreate: [], - references: [], - windowOldRoute: { - path: '', - fullPath: '', - query: {} - }, - dataLog: {}, // { containerUuid, recordId, tableName, eventType } - tabSequenceRecord: [], - totalResponse: 0, - totalRequest: 0 -} - -const windowControl = { - state: initStateWindowControl, - mutations: { - addInCreate(state, payload) { - state.inCreate.push(payload) - }, - deleteInCreate(state, payload) { - state.inCreate = state.inCreate.filter(item => item.containerUuid !== payload.containerUuid) - }, - addReferencesList(state, payload) { - state.references.push(payload) - }, - setDataLog(state, payload) { - state.dataLog = payload - }, - setWindowOldRoute(state, payload) { - state.windowOldRoute = payload - }, - setTabSequenceRecord(state, payload) { - state.tabSequenceRecord = payload - }, - setTotalResponse(state, payload) { - state.totalResponse = payload - }, - setTotalRequest(state, payload) { - state.totalRequest = payload - }, - resetStateWindowControl(state) { - state = initStateWindowControl - } - }, - actions: { - undoPanelToNew({ dispatch, rootGetters }, { containerUuid }) { - const oldAttributes = rootGetters.getColumnNamesAndValues({ - containerUuid, - propertyName: 'oldValue', - isObjectReturn: true, - isAddDisplayColumn: true - }) - dispatch('notifyPanelChange', { - containerUuid, - newValues: oldAttributes - }) - }, - createNewEntity({ commit, dispatch, getters, rootGetters }, { - parentUuid, - containerUuid - }) { - return new Promise((resolve, reject) => { - // exists some call to create new record with container uuid - if (getters.getInCreate(containerUuid)) { - return reject({ - error: 0, - message: `In this panel (${containerUuid}) is a create new record in progress` - }) - } - - const { tableName, fieldList } = rootGetters.getPanel(containerUuid) - // delete key from attributes - const attributesList = rootGetters.getColumnNamesAndValues({ - containerUuid, - propertyName: 'value', - isEvaluateValues: true, - isAddDisplayColumn: false - }) - - commit('addInCreate', { - containerUuid, - tableName, - attributesList - }) - createEntity({ - tableName, - attributesList - }) - .then(createEntityResponse => { - const newValues = createEntityResponse.values - attributesList.forEach(element => { - if (element.columnName.includes('DisplayColumn')) { - newValues[element.columnName] = element.value - } - }) - - showMessage({ - message: language.t('data.createRecordSuccessful'), - type: 'success' - }) - - // update fields with new values - dispatch('notifyPanelChange', { - parentUuid, - containerUuid, - newValues, - isSendToServer: false - }) - dispatch('addNewRow', { - parentUuid, - containerUuid, - isPanelValues: true, - isEdit: false - }) - - // set data log to undo action - const fieldId = fieldList.find(itemField => itemField.isKey) - dispatch('setDataLog', { - containerUuid, - tableName, - recordId: fieldId.value, // TODO: Verify performance with tableName_ID - recordUuid: newValues.UUID, - eventType: 'INSERT' - }) - - const oldRoute = router.app._route - router.push({ - name: oldRoute.name, - params: { - ...oldRoute.params - }, - query: { - ...oldRoute.query, - action: createEntityResponse.uuid - } - }) - dispatch('tagsView/delView', oldRoute, true) - - resolve({ - data: newValues, - recordUuid: createEntityResponse.uuid, - recordId: createEntityResponse.id, - tableName: createEntityResponse.tableName - }) - }) - .catch(error => { - showMessage({ - message: error.message, - type: 'error' - }) - console.warn(`Create Entity error: ${error.message}.`) - reject(error) - }) - .finally(() => { - commit('deleteInCreate', { - containerUuid, - tableName, - attributesList - }) - }) - }) - }, - createEntityFromTable({ commit, dispatch, getters, rootGetters }, { - parentUuid, - containerUuid, - row - }) { - // exists some call to create new record with container uuid - if (getters.getInCreate(containerUuid)) { - return { - error: 0, - message: `In this panel (${containerUuid}) is a create new record in progress.` - } - } - const { tableName, isParentTab } = rootGetters.getPanel(containerUuid) - - // TODO: Add support to Binary columns (BinaryData) - const columnsToDontSend = ['BinaryData', 'isEdit', 'isNew', 'isSendServer'] - - // TODO: Evaluate peformance without filter using delete(prop) before convert object to array - // attributes or fields - const fieldsList = getters.getFieldsListFromPanel(containerUuid) - const attributesList = [] - fieldsList.forEach(itemAttribute => { - if (columnsToDontSend.includes(itemAttribute.columnName) || itemAttribute.columnName.includes('DisplayColumn')) { - return false - } - if (isEmptyValue(row[itemAttribute.columnName])) { - return false - } - - attributesList.push({ - value: row[itemAttribute.columnName], - columnName: itemAttribute.columnName, - valueType: itemAttribute.valueType - }) - }) - - commit('addInCreate', { - containerUuid, - tableName, - attributesList - }) - - let isError = false - return createEntity({ - tableName, - attributesList - }) - .then(createEntityResponse => { - showMessage({ - message: language.t('data.createRecordSuccessful'), - type: 'success' - }) - if (isParentTab) { - // redirect to create new record - const oldRoute = router.app._route - router.push({ - name: oldRoute.name, - params: { - ...oldRoute.params - }, - query: { - ...oldRoute.query, - action: createEntityResponse.recordUuid - } - }) - } - return { - data: createEntityResponse.values, - ...createEntityResponse - } - }) - .catch(error => { - showMessage({ - message: error.message, - type: 'error' - }) - console.warn(`Create Entity Table Error ${error.code}: ${error.message}.`) - isError = true - }) - .finally(() => { - if (isError) { - dispatch('addNewRow', { - containerUuid, - row - }) - } else { - // refresh record list - dispatch('getDataListTab', { - parentUuid, - containerUuid - }) - .catch(error => { - console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) - }) - } - commit('deleteInCreate', { - containerUuid, - tableName, - attributesList - }) - }) - }, - updateCurrentEntity({ dispatch, rootGetters }, { - containerUuid, - recordUuid = null - }) { - const panel = rootGetters.getPanel(containerUuid) - if (!recordUuid) { - recordUuid = rootGetters.getUuid(containerUuid) - } - - // TODO: Add support to Binary columns (BinaryData) - const columnsToDontSend = ['Account_Acct'] - - // attributes or fields - let finalAttributes = rootGetters.getColumnNamesAndValues({ - containerUuid: containerUuid, - isEvaluatedChangedValue: true - }) - - finalAttributes = finalAttributes.filter(itemAttribute => { - if (columnsToDontSend.includes(itemAttribute.columnName) || itemAttribute.columnName.includes('DisplayColumn')) { - return false - } - const field = panel.fieldList.find(itemField => itemField.columnName === itemAttribute.columnName) - if (!field || !field.isUpdateable || !field.isDisplayed) { - return false - } - return true - }) - return updateEntity({ - tableName: panel.tableName, - recordUuid, - attributesList: finalAttributes - }) - .then(updateEntityResponse => { - const newValues = updateEntityResponse.values - // set data log to undo action - // TODO: Verify performance with tableName_ID - let recordId = updateEntityResponse.id - if (isEmptyValue(recordId)) { - recordId = newValues[`${panel.tableName}_ID`] - } - if (isEmptyValue(recordId)) { - const fieldId = panel.fieldList.find(itemField => itemField.isKey) - recordId = fieldId.value - } - - if (isEmptyValue(recordUuid)) { - recordUuid = updateEntityResponse.uuid - } - if (isEmptyValue(recordUuid)) { - recordUuid = newValues.UUID - } - - dispatch('setDataLog', { - containerUuid, - tableName: panel.tableName, - recordId, - recordUuid, - eventType: 'UPDATE' - }) - if (rootGetters.getShowContainerInfo) { - dispatch('listRecordLogs', { - tableName: panel.tableName, - recordId - }) - } - return newValues - }) - .catch(error => { - showMessage({ - message: error.message, - type: 'error' - }) - console.warn(`Update Entity Error ${error.code}: ${error.message}`) - }) - }, - updateCurrentEntityFromTable({ rootGetters }, { - containerUuid, - row - }) { - const { tableName, fieldList } = rootGetters.getPanel(containerUuid) - - // TODO: Add support to Binary columns (BinaryData) - const columnsToDontSend = ['BinaryData', 'isEdit', 'isNew', 'isSendServer'] - - // TODO: Evaluate peformance without filter using delete(prop) before convert object to array - // attributes or fields - let finalAttributes = convertObjectToArrayPairs(row) - finalAttributes = finalAttributes.filter(itemAttribute => { - if (columnsToDontSend.includes(itemAttribute.columnName) || itemAttribute.columnName.includes('DisplayColumn')) { - return false - } - const field = fieldList.find(itemField => itemField.columnName === itemAttribute.columnName) - if (!field || !field.isUpdateable || !field.isDisplayed) { - return false - } - return true - }) - - return updateEntity({ - tableName, - recordUuid: row.UUID, - attributesList: finalAttributes - }) - .then(response => { - return response - }) - .catch(error => { - showMessage({ - message: error.message, - type: 'error' - }) - console.warn(`Update Entity Table Error ${error.code}: ${error.message}.`) - }) - }, - /** - * Update record after run process associated with window - * @param {string} parentUuid - * @param {string} containerUuid - * @param {object} tab - */ - updateRecordAfterRunProcess({ dispatch, rootGetters }, { - parentUuid, - containerUuid, - tab - }) { - const recordUuid = rootGetters.getUuid(containerUuid) - // get new values - dispatch('getEntity', { - parentUuid, - containerUuid, - tableName: tab.tableName, - recordUuid - }) - .then(response => { - // update panel - if (tab.isParentTab) { - dispatch('notifyPanelChange', { - parentUuid, - containerUuid, - newValues: response, - isSendCallout: false, - isSendToServer: false - }) - } - // update row in table - dispatch('notifyRowTableChange', { - parentUuid, - containerUuid, - row: response, - isEdit: false - }) - }) - }, - deleteEntity({ dispatch, rootGetters }, { - parentUuid, - containerUuid, - recordUuid, - recordId, - row - }) { - return new Promise(resolve => { - const panel = rootGetters.getPanel(containerUuid) - if (!isEmptyValue(row)) { - recordUuid = row.UUID - recordId = row[`${panel.tableName}_ID`] - } - - deleteEntity({ - tableName: panel.tableName, - recordUuid, - recordId - }) - .then(responseDeleteEntity => { - // refresh record list - dispatch('getDataListTab', { - parentUuid, - containerUuid - }) - .then(responseDataList => { - if (panel.isParentTab) { - // if response is void, go to new record - if (responseDataList.length <= 0) { - dispatch('resetPanelToNew', { - parentUuid, - containerUuid, - panelType: 'window', - isNewRecord: true - }) - } else { - const oldRoute = router.app._route - // else display first record of table in panel - router.push({ - name: oldRoute.name, - params: { - ...oldRoute.params - }, - query: { - ...oldRoute.query, - action: responseDataList[0].UUID - } - }) - } - } - }) - .catch(error => { - console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) - }) - showMessage({ - message: language.t('data.deleteRecordSuccessful'), - type: 'success' - }) - - if (isEmptyValue(recordId)) { - // TODO: Verify performance with tableName_ID - const fieldId = panel.fieldList.find(itemField => itemField.isKey) - recordId = fieldId.value - } - // set data log to undo action - dispatch('setDataLog', { - containerUuid, - tableName: panel.tableName, - recordId, - recordUuid, - eventType: 'DELETE' - }) - - resolve(responseDeleteEntity) - }) - .catch(error => { - showMessage({ - message: language.t('data.deleteRecordError'), - type: 'error' - }) - console.warn(`Delete Entity - Error ${error.message}, Code: ${error.code}.`) - }) - }) - }, - /** - * Delete selection records in table - * @param {string} parentUuid - * @param {string} containerUuid - * @param {string} tableName - * @param {boolean} isParentTab - */ - deleteSelectionDataList({ dispatch, rootGetters }, { - parentUuid, - containerUuid, - tableName, - isParentTab - }) { - if (isEmptyValue(tableName) || isEmptyValue(isParentTab)) { - const tab = rootGetters.getTab(parentUuid, containerUuid) - tableName = tab.tableName - isParentTab = tab.isParentTab - } - const allData = rootGetters.getDataRecordAndSelection(containerUuid) - let selectionLength = allData.selection.length - - allData.selection.forEach((record, index) => { - // validate if the registry row has no uuid before sending to the server - if (isEmptyValue(record.UUID)) { - selectionLength = selectionLength - 1 - console.warn(`This row does not contain a record with UUID`, record) - // refresh record list - dispatch('getDataListTab', { - parentUuid, - containerUuid - }) - .catch(error => { - console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) - }) - return - } - deleteEntity({ - tableName, - recordUuid: record.UUID - }) - .then(() => { - if (isParentTab) { - // redirect to create new record - const oldRoute = router.app._route - if (record.UUID === oldRoute.query.action) { - router.push({ - name: oldRoute.name, - params: { - ...oldRoute.params - }, - query: { - ...oldRoute.query, - action: 'create-new' - } - }) - // clear fields with default values - dispatch('resetPanelToNew', { - parentUuid, - containerUuid - }) - // delete view with uuid record delete - dispatch('tagsView/delView', oldRoute, true) - } - } - - if ((index + 1) >= selectionLength) { - // refresh record list - dispatch('getDataListTab', { - parentUuid, - containerUuid - }) - .catch(error => { - console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) - }) - showMessage({ - message: language.t('data.deleteRecordSuccessful'), - type: 'success' - }) - } - }) - }) - }, - undoModifyData({ getters }, { - containerUuid, - recordUuid - }) { - return rollbackEntity(getters.getDataLog(containerUuid, recordUuid)) - .then(response => { - return response - }) - .catch(error => { - showMessage({ - message: error.message, - type: 'error' - }) - console.warn(`Rollback Entity error: ${error.message}. Code: ${error.code}.`) - }) - }, - setDataLog({ commit }, { - containerUuid, - tableName, - recordId, - recordUuid, - eventType - }) { - commit('setDataLog', { - containerUuid, - tableName, - recordId, - recordUuid, - eventType - }) - }, - /** - * Get data to table in tab - * @param {string} parentUuid, window to search record data - * @param {string} containerUuid, tab to search record data - * @param {string} recordUuid, uuid to search - * @param {boolean} isRefreshPanel, if main panel is updated with new response data - * @param {boolean} isLoadAllRecords, if main panel is updated with new response data - */ - getDataListTab({ dispatch, rootGetters }, { - parentUuid, - containerUuid, - recordUuid, - referenceWhereClause = '', - columnName, - value, - criteria, - isAddRecord = false, - isLoadAllRecords = false, - isRefreshPanel = false, - isReference = false, - isShowNotification = true - }) { - const tab = rootGetters.getTab(parentUuid, containerUuid) - - let parsedQuery = tab.query - if (!isEmptyValue(parsedQuery) && parsedQuery.includes('@')) { - parsedQuery = parseContext({ - parentUuid, - containerUuid, - value: tab.query, - isBooleanToString: true - }).value - } - - let parsedWhereClause = tab.whereClause - if (!isEmptyValue(parsedWhereClause) && parsedWhereClause.includes('@')) { - parsedWhereClause = parseContext({ - parentUuid, - containerUuid, - value: tab.whereClause, - isBooleanToString: true - }).value - } - - if (isReference) { - if (!isEmptyValue(parsedWhereClause)) { - parsedWhereClause += ` AND ${referenceWhereClause}` - } else { - parsedWhereClause += referenceWhereClause - } - } - - if (!isEmptyValue(criteria)) { - if (!isEmptyValue(parsedWhereClause)) { - parsedWhereClause += ` AND ${criteria.whereClause}` - } else { - parsedWhereClause += criteria.whereClause - } - } - - const conditionsList = [] - // TODO: evaluate if overwrite values to conditions - if (!isLoadAllRecords && tab.isParentTab && !isEmptyValue(tab.tableName) && !isEmptyValue(value)) { - conditionsList.push({ - columnName, - value - }) - } - return dispatch('getObjectListFromCriteria', { - parentUuid, - containerUuid, - tableName: tab.tableName, - query: parsedQuery, - whereClause: parsedWhereClause, - orderByClause: tab.orderByClause, - conditionsList, - isParentTab: tab.isParentTab, - isAddRecord, - isShowNotification - }) - .then(response => { - if (isRefreshPanel && !isEmptyValue(recordUuid) && recordUuid !== 'create-new') { - const newValues = response.find(itemData => itemData.UUID === recordUuid) - if (newValues) { - // update fields with values obtained from the server - dispatch('notifyPanelChange', { - parentUuid, - containerUuid, - newValues, - isSendCallout: false, - isSendToServer: false - }) - } else { - // this record is missing (Deleted or the query does not include it) - dispatch('resetPanelToNew', { - parentUuid, - containerUuid - }) - } - } - return response - }) - .catch(error => { - return error - }) - .finally(() => { - const currentData = rootGetters.getDataRecordAndSelection(containerUuid) - const { originalNextPageToken, pageNumber, recordCount } = currentData - let nextPage = pageNumber - const isAdd = isAddRecord - if (originalNextPageToken && isAddRecord) { - const pageInToken = originalNextPageToken.substring(originalNextPageToken.length - 2) - if (pageInToken === '-1') { - isAddRecord = false - } - if (pageNumber === 1 && recordCount > 50) { - nextPage = nextPage + 1 - isAddRecord = true - } - } else { - isAddRecord = false - } - if (recordCount <= 50) { - isAddRecord = false - } - - if (isAddRecord) { - dispatch('setPageNumber', { - parentUuid, - containerUuid, - pageNumber: nextPage, - panelType: 'window', - isAddRecord, - isShowNotification: false - }) - } - if (isAdd && isAdd !== isAddRecord) { - if (tab.isSortTab) { - const record = rootGetters.getDataRecordsList(containerUuid) - const recordToTab = record - .map(itemRecord => { - return { - ...itemRecord - } - }) - .sort((itemA, itemB) => { - return itemA[tab.sortOrderColumnName] - itemB[tab.sortOrderColumnName] - }) - dispatch('setTabSequenceRecord', recordToTab) - } - } - }) - }, - /** - * Get references asociate to record - * @param {string} parentUuid as windowUuid - * @param {string} containerUuid - * @param {string} tableName - * @param {string} recordUuid - */ - getReferencesListFromServer({ commit, rootGetters }, { - parentUuid: windowUuid, - containerUuid, - tableName, - recordUuid - }) { - if (isEmptyValue(tableName)) { - tableName = rootGetters.getTab(windowUuid, containerUuid).tableName - } - return new Promise(resolve => { - getReferencesList({ - windowUuid, - tableName, - recordUuid - }) - .then(referenceResponse => { - const referencesList = referenceResponse.referencesList.map(item => { - return { - ...item, - recordUuid, - type: 'reference' - } - }) - const references = { - ...referenceResponse, - windowUuid, - recordUuid, - referencesList - } - commit('addReferencesList', references) - resolve(referenceResponse) - }) - .catch(error => { - console.warn(`References Load Error ${error.code}: ${error.message}.`) - }) - }) - }, - setWindowOldRoute({ commit }, oldPath = { path: '', fullPath: '', query: {}}) { - commit('setWindowOldRoute', oldPath) - }, - setTabSequenceRecord({ commit }, record) { - commit('setTabSequenceRecord', record) - }, - /** - * Update records in tab sort - * @param {string} containerUuid - * @param {string} parentUuid - */ - updateSequence({ state, commit, dispatch, getters, rootGetters }, { - parentUuid, - containerUuid - }) { - const { tableName, sortOrderColumnName, sortYesNoColumnName, tabAssociatedUuid } = rootGetters.getTab(parentUuid, containerUuid) - const listSequenceToSet = getters.getTabSequenceRecord - const recordData = rootGetters.getDataRecordsList(containerUuid) - - // scrolls through the logs and checks if there is a change to be sent to server - recordData.forEach(itemData => { - const dataSequence = listSequenceToSet.find(item => item.UUID === itemData.UUID) - if (itemData[sortOrderColumnName] === dataSequence[sortOrderColumnName]) { - return - } - const valuesToSend = [{ - columnName: sortOrderColumnName, - value: dataSequence[sortOrderColumnName] - }] - - if (itemData[sortYesNoColumnName] !== dataSequence[sortYesNoColumnName]) { - valuesToSend.push({ - columnName: sortYesNoColumnName, - value: dataSequence[sortYesNoColumnName] - }) - } - - const countRequest = state.totalRequest + 1 - commit('setTotalRequest', countRequest) - - updateEntity({ - tableName, - recordUuid: itemData.UUID, - attributesList: valuesToSend - }) - .catch(error => { - showMessage({ - message: error.message, - type: 'error' - }) - console.warn(`Update Entity Table Error ${error.code}: ${error.message}`) - }) - .finally(() => { - const countResponse = state.totalResponse + 1 - commit('setTotalResponse', countResponse) - if (state.totalResponse === state.totalRequest) { - showMessage({ - message: language.t('notifications.updateSuccessfully'), - type: 'success' - }) - dispatch('setShowDialog', { - type: 'window', - action: undefined - }) - commit('setTotalRequest', 0) - commit('setTotalResponse', 0) - - dispatch('setRecordSelection', { - parentUuid, - containerUuid, - isLoaded: false - }) - dispatch('setTabSequenceRecord', []) - - // refresh record list in table source - dispatch('getDataListTab', { - parentUuid, - containerUuid: tabAssociatedUuid - }) - .catch(error => { - console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) - }) - } - }) - }) - } - }, - getters: { - getInCreate: (state) => (containerUuid) => { - return state.inCreate.find(item => item.containerUuid === containerUuid) - }, - getReferencesList: (state) => (windowUuid, recordUuid) => { - return state.references.find(item => item.windowUuid === windowUuid && item.recordUuid === recordUuid) - }, - getReferencesInfo: (state, getters) => ({ windowUuid, recordUuid, referenceUuid }) => { - const references = getters.getReferencesList(windowUuid, recordUuid) - return references.referencesList.find(item => item.uuid === referenceUuid) - }, - getTabSequenceRecord: (state) => { - return state.tabSequenceRecord - }, - getDataLog: (state) => (containerUuid, recordUuid) => { - const current = state.dataLog - if (current.containerUuid === containerUuid && - ((current.recordUuid === recordUuid) || - (current.eventType === 'DELETE' && recordUuid === 'create-new'))) { - return current - } - return undefined - } - } -} - -export default windowControl diff --git a/src/store/modules/ADempiere/windowDefinition.js b/src/store/modules/ADempiere/windowDefinition.js new file mode 100644 index 00000000..9e7349fd --- /dev/null +++ b/src/store/modules/ADempiere/windowDefinition.js @@ -0,0 +1,452 @@ +import { + getWindow as getWindowMetadata, + getTab as getTabMetadata +} from '@/api/ADempiere/dictionary' +import { showMessage } from '@/utils/ADempiere/notification' +import { isEmptyValue } from '@/utils/ADempiere/valueUtils' +import language from '@/lang' +import router from '@/router' +import { generateField } from '@/utils/ADempiere/dictionaryUtils' +import { getFieldTemplate } from '@/utils/ADempiere/lookupFactory' + +const initStateWindow = { + window: [], + windowIndex: 0 +} + +const window = { + state: initStateWindow, + mutations: { + addWindow(state, payload) { + state.window.push(payload) + state.windowIndex++ + }, + dictionaryResetCacheWindow(state) { + state = initStateWindow + }, + setCurrentTab(state, payload) { + payload.window.currentTab = payload.tab + payload.window.currentTabUuid = payload.tab.uuid + }, + changeWindowAttribute(state, payload) { + let value = payload.attributeValue + if (payload.attributeNameControl) { + value = payload.window[payload.attributeNameControl] + } + payload.window[payload.attributeName] = value + }, + changeTabAttribute(state, payload) { + let value = payload.attributeValue + if (payload.attributeNameControl) { + value = payload.tab[payload.attributeNameControl] + } + payload.tab[payload.attributeName] = value + } + }, + actions: { + /** + * Get Window metadata from server + * @param {string} windowUuid + * @param {number} windowId + * @param {object} routeToDelete, route to close in tagView when fail + */ + getWindowFromServer({ commit, state, dispatch }, { + windowUuid, + windowId, + routeToDelete + }) { + return getWindowMetadata({ + uuid: windowUuid, + id: windowId + }) + .then(responseWindow => { + const firstTabTableName = responseWindow.tabsList[0].tableName + const firstTabUuid = responseWindow.tabsList[0].uuid + const tabsListParent = [] + const tabsListChildren = [] + + const tabsSequence = [] + // TODO Add source tab on the server for tabs Translation and Sort + const tabs = responseWindow.tabsList.filter(itemTab => { + if (itemTab.isSortTab) { + // TODO: Add convert tab as process function + tabsSequence.push({ + uuid: itemTab.uuid, + id: itemTab.id, + parentUuid: windowUuid, + containerUuid: itemTab.uuid, + parentTabUuid: itemTab.parentTabUuid, + panelType: 'window', + type: 'sequence', + isSortTab: itemTab.isSortTab, + name: itemTab.name, + description: itemTab.description, + tableName: itemTab.tableName, + sortOrderColumnName: itemTab.sortOrderColumnName, // order column + sortYesNoColumnName: itemTab.sortYesNoColumnName // included column + }) + } + // TODO: Add support to isAdvancedTab, isTranslationTab and isHasTree + return !itemTab.isTranslationTab + }).map((tabItem, index, list) => { + // let tab = tabItem + const tab = { + ...tabItem, + containerUuid: tabItem.uuid, + parentUuid: windowUuid, + windowUuid, + tabGroup: tabItem.fieldGroup, + firstTabUuid, + // relations + isParentTab: Boolean(firstTabTableName === tabItem.tableName), + // app properties + isAssociatedTabSequence: false, // show modal with order tab + isShowedRecordNavigation: !(tabItem.isSingleRow), + isLoadFieldsList: false, + index + } + delete tab.processesList + + // action is dispatch used in vuex + let actions = [] + actions.push({ + // action to set default values and enable fields not isUpdateable + name: language.t('window.newRecord'), + processName: language.t('window.newRecord'), + type: 'dataAction', + action: 'setDefaultValues', + uuidParent: windowUuid, + disabled: !tab.isInsertRecord || tab.isReadOnly + }, { + // action to delete record selected + name: language.t('window.deleteRecord'), + processName: language.t('window.deleteRecord'), + type: 'dataAction', + action: 'deleteEntity', + uuidParent: windowUuid, + disabled: tab.isReadOnly + }, { + // action to undo create, update, delete record + name: language.t('data.undo'), + processName: language.t('data.undo'), + type: 'dataAction', + action: 'undoModifyData', + uuidParent: windowUuid, + disabled: false + }, { + name: language.t('data.lockRecord'), + processName: language.t('data.lockRecord'), + type: 'dataAction', + action: 'lockRecord', + disabled: false, + hidden: true, + tableName: '', + recordId: null + }, { + name: language.t('data.unlockRecord'), + processName: language.t('data.unlockRecord'), + type: 'dataAction', + action: 'unlockRecord', + disabled: false, + hidden: true, + tableName: '', + recordId: null + }) + + if (tab.isSortTab) { + const tabParent = list.find(itemTab => itemTab.tableName === tab.tableName && !itemTab.isSortTab) + if (tabParent) { + tab.tabAssociatedUuid = tabParent.uuid // tab source uuid + tab.tabAssociatedName = tabParent.name // tab source name + } + } else { + // add tabs sequence associated as process in tab source + let orderTabs = tabsSequence.filter(itemTab => itemTab.tableName === tab.tableName) + if (orderTabs.length) { + orderTabs = orderTabs.map(itemTab => { + return { + ...itemTab, + // appication attributes + tabAssociatedUuid: tab.uuid, // tab source + tabAssociatedName: tab.name, // tab source + action: 'orderSequence', + panelType: 'window', + type: 'application' + } + }) + actions = actions.concat(orderTabs) + tab.isAssociatedTabSequence = true + tab.tabsOrder = orderTabs + } + } + + // get processess associated in tab + if (tabItem.processesList && tabItem.processesList.length) { + const processList = tabItem.processesList.map(processItem => { + // TODO: No list of parameters + // add process associated in vuex store + // dispatch('addProcessAssociated', { + // processToGenerate: processItem, + // containerUuidAssociated: tabItem.uuid + // }) + return { + id: processItem.id, + uuid: processItem.uuid, + name: processItem.name, + type: 'process', + panelType: 'process', + description: processItem.description, + help: processItem.help, + isReport: processItem.isReport, + isDirectPrint: processItem.isDirectPrint, + containerUuidAssociated: tabItem.uuid, + parentUuidAssociated: windowUuid, + panelTypeAssociated: 'window' + } + }) + actions = actions.concat(processList) + } + // Add process menu + dispatch('setContextMenu', { + containerUuid: tab.uuid, + actions + }) + + if (tab.isParentTab) { + tabsListParent.push(tab) + return tab + } + if (!tab.isSortTab) { + tabsListChildren.push(tab) + } + return tab + }) + + const newWindow = { + ...responseWindow, + tabsList: tabs, + currentTab: tabsListParent[0], + tabsListParent, + tabsListChildren, + // app attributes + currentTabUuid: tabsListParent[0].uuid, + firstTab: tabsListParent[0], + firstTabUuid, + windowIndex: state.windowIndex + 1, + // App properties + isShowedTabsChildren: Boolean(tabsListChildren.length), + isShowedRecordNavigation: undefined, + isShowedAdvancedQuery: false + } + commit('addWindow', newWindow) + return newWindow + }) + .catch(error => { + router.push({ path: '/dashboard' }) + dispatch('tagsView/delView', routeToDelete) + showMessage({ + message: language.t('login.unexpectedError'), + type: 'error' + }) + console.warn(`Dictionary Window (State Window) - Error ${error.code}: ${error.message}.`) + }) + }, + getTabAndFieldFromServer({ dispatch, getters }, { + parentUuid, + containerUuid, + tabId, + panelType = 'window', + panelMetadata, + isAdvancedQuery = false + }) { + return new Promise((resolve, reject) => { + getTabMetadata({ + uuid: containerUuid, + id: tabId + }) + .then(tabResponse => { + const additionalAttributes = { + parentUuid, + containerUuid, + isShowedFromUser: true, + panelType, + tableName: tabResponse.tableName, + // + isReadOnlyFromForm: false, + isAdvancedQuery, + isEvaluateValueChanges: !isAdvancedQuery + } + + let isWithUuidField = false // indicates it contains the uuid field + let fieldLinkColumnName + // Convert and add to app attributes + const fieldsList = tabResponse.fieldsList.map((fieldItem, index) => { + fieldItem = generateField({ + fieldToGenerate: fieldItem, + moreAttributes: { + ...additionalAttributes, + fieldListIndex: index + } + }) + + if (!isWithUuidField && fieldItem.columnName === 'UUID') { + isWithUuidField = true + } + + if (fieldItem.isParent) { + fieldLinkColumnName = fieldItem.columnName + } + + return fieldItem + }) + + let isTabsChildren = false + if (!isAdvancedQuery) { + const window = getters.getWindow(parentUuid) + isTabsChildren = Boolean(window.tabsListChildren.length) + } + + if (!isWithUuidField) { + const fieldUuid = getFieldTemplate({ + ...additionalAttributes, + isShowedFromUser: false, + name: 'UUID', + columnName: 'UUID', + componentPath: 'FieldText' + }) + fieldsList.push(fieldUuid) + } + + if (isEmptyValue(panelMetadata)) { + panelMetadata = getters.getTab(parentUuid, containerUuid) + } + // Panel for save on store + const panel = { + ...panelMetadata, + isAdvancedQuery, + fieldLinkColumnName, + fieldList: fieldsList, + panelType, + // app attributes + isLoadFieldsList: true, + isShowedTotals: false, + isTabsChildren // to delete records assiciated + } + + dispatch('addPanel', panel) + resolve(panel) + + dispatch('changeTabAttribute', { + parentUuid, + containerUuid, + tab: panelMetadata, + attributeName: 'isLoadFieldsList', + attributeValue: true + }) + }) + .catch(error => { + showMessage({ + message: language.t('login.unexpectedError'), + type: 'error' + }) + console.warn(`Get Dictionary Tab (State Window) - Error ${error.code}: ${error.message}.`, error) + reject(error) + }) + }) + }, + setCurrentTab({ commit, getters }, { + parentUuid, + containerUuid, + window, + tab + }) { + if (isEmptyValue(window)) { + window = getters.getWindow(parentUuid) + } + if (isEmptyValue(tab)) { + tab = window.tabsList.find(itemTab => itemTab.uuid === containerUuid) + } + + commit('setCurrentTab', { + window, + tab + }) + }, + changeWindowAttribute({ commit, getters }, { + parentUuid, + window, + attributeName, + attributeNameControl, + attributeValue + }) { + if (isEmptyValue(window)) { + window = getters.getWindow(parentUuid) + } + + commit('changeWindowAttribute', { + parentUuid, + window, + attributeName, + attributeNameControl, + attributeValue + }) + }, + changeTabAttribute({ commit, getters }, { + parentUuid, + containerUuid, + tab, + attributeName, + attributeNameControl, + attributeValue + }) { + if (isEmptyValue(tab)) { + tab = getters.getTab(parentUuid, containerUuid) + } + commit('changeTabAttribute', { + tab, + attributeName, + attributeValue, + attributeNameControl + }) + } + }, + getters: { + getWindow: (state) => (windowUuid) => { + return state.window.find( + item => item.uuid === windowUuid + ) + }, + getIsShowedRecordNavigation: (state, getters) => (windowUuid) => { + const window = getters.getWindow(windowUuid) + if (window) { + return window.isShowedRecordNavigation + } + return window + }, + getTab: (state, getters) => (windowUuid, tabUuid) => { + const window = getters.getWindow(windowUuid) + if (window) { + return window.tabsList.find(tabItem => { + return tabItem.uuid === tabUuid + }) + } + return window + }, + getCurrentTab: (state, getters) => (windowUuid) => { + const window = getters.getWindow(windowUuid) + if (window) { + return window.tabsList.find(tabItem => { + return tabItem.uuid === window.currentTabUuid + }) + } + return { + isInsertRecord: false + } + }, + getTableNameFromTab: (state, getters) => (windowUuid, tabUuid) => { + return getters.getTab(windowUuid, tabUuid).tableName + } + } +} + +export default window diff --git a/src/store/modules/user.js b/src/store/modules/user.js index 32e85c20..146c3032 100644 --- a/src/store/modules/user.js +++ b/src/store/modules/user.js @@ -157,7 +157,9 @@ const actions = { // TODO: return #Date as long data type Date (5) responseGetInfo.defaultContextMap.set('#Date', new Date()) // set multiple context - dispatch('setMultipleContextMap', responseGetInfo.defaultContextMap, { + dispatch('setMultiplePreference', { + values: responseGetInfo.defaultContextMap + }, { root: true }) @@ -295,7 +297,7 @@ const actions = { console.warn(`Error ${error.code} getting Organizations list: ${error.message}.`) }) }, - changeOrganization({ commit, dispatch }, { + changeOrganization({ dispatch }, { organizationUuid }) { setCurrentOrganization(organizationUuid) diff --git a/src/utils/ADempiere/contextUtils.js b/src/utils/ADempiere/contextUtils.js index 2007ad73..ce016012 100644 --- a/src/utils/ADempiere/contextUtils.js +++ b/src/utils/ADempiere/contextUtils.js @@ -1,4 +1,5 @@ -import { isEmptyValue } from '@/utils/ADempiere/valueUtils' +import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js' +import { convertBooleanToString } from '@/utils/ADempiere/valueFormat.js' import evaluator from '@/utils/ADempiere/evaluator' import store from '@/store' @@ -10,13 +11,89 @@ export const getContext = ({ containerUuid, columnName }) => { - return store.getters.getContext({ - parentUuid, - containerUuid, - columnName - }) + let value + const isPreferenceValue = columnName.startsWith('$') || columnName.startsWith('#') + if (isPreferenceValue || columnName.startsWith(`P|${parentUuid}`) || columnName.startsWith(`P|${columnName}`)) { + value = store.getters.getPreference({ + parentUuid, + containerUuid, + columnName + }) + } + if (!isPreferenceValue && isEmptyValue(value)) { + value = store.getters.getValueOfContainer({ + parentUuid, + containerUuid, + columnName + }) + } + return value } +/** + * Get Preference. + *
+ *      0)  Current Setting
+ *      1)  Window Preference
+ *      2)  Global Preference
+ *      3)  Login settings
+ *      4)  Accounting settings
+ *  
+ * @param {string} parentUuid UUID Window + * @param {string} containerUuid UUID Tab, Process, SmartBrowser, Report and Form + * @param {string} columnName (context) Entity to search + * @return preference value + */ +export function getPreference({ + parentUuid, + containerUuid, + columnName +}) { + let value + if (isEmptyValue(columnName)) { + console.warn('Require Context ColumnName') + return value + } + + // USER PREFERENCES + // View Preferences + if (parentUuid) { + value = getContext({ + parentUuid: 'P' + parentUuid, + containerUuid, + columnName + }) + if (!isEmptyValue(value)) { + return value + } + } + + // Global Preferences + value = getContext({ + columnName: 'P|' + columnName + }) + if (!isEmptyValue(value)) { + return value + } + + // SYSTEM PREFERENCES + // Login setting + // get # globals context only window + value = getContext({ + columnName: '#' + columnName + }) + if (!isEmptyValue(value)) { + return value + } + + // Accounting setting + value = getContext({ + columnName: '$' + columnName + }) + + return value +} // getPreference + /** * Extracts the associated fields from the logics or default values * @param {string} displayLogic @@ -50,6 +127,12 @@ export function getParentFields({ return parentFields } +export const specialColumns = [ + 'C_AcctSchema_ID', + 'C_Currency_ID', + 'C_Convertion_Type_ID' +] + /** * Parse Context String * @param {string} value: (REQUIRED) String to parsing @@ -71,17 +154,22 @@ export function parseContext({ }) { let isError = false const errorsList = [] - value = String(value) + if (isEmptyValue(value)) { + value = undefined + if (specialColumns.includes(columnName)) { + value = contextInfo = getContext({ + columnName: '$' + columnName + }) + } + return { - value: undefined, + value, isError: true, - errorsList: [] + errorsList } } - if (value.includes('@SQL=')) { - value = value.replace('@SQL=', '') - } + value = String(value).replace('@SQL=') // const instances = value.length - value.replace('@', '').length // if ((instances > 0) && (instances % 2) !== 0) { // could be an email address // return value @@ -92,12 +180,6 @@ export function parseContext({ let outString = '' let firstIndexTag = inString.indexOf('@') - const convertBooleanToString = (booleanValue) => { - if (booleanValue) { - return 'Y' - } - return 'N' - } while (firstIndexTag !== -1) { outString = outString + inString.substring(0, firstIndexTag) // up to @ @@ -122,23 +204,32 @@ export function parseContext({ containerUuid, columnName }) // get context + + if (isEmptyValue(contextInfo)) { + // get global context + if (token.startsWith('#') || token.startsWith('$')) { + contextInfo = getContext({ + columnName + }) + } else { + // get accounting context + if (specialColumns.includes(columnName)) { + contextInfo = getContext({ + columnName: '$' + columnName + }) + } + } + } + + // menu attribute isEmptyValue isSOTrx + if (!isEmptyValue(isSOTrxMenu) && token === 'IsSOTrx' && isEmptyValue(contextInfo)) { + contextInfo = isSOTrxMenu + } + if ((isBooleanToString || isSQL) && typeof contextInfo === 'boolean') { contextInfo = convertBooleanToString(contextInfo) } - if (isEmptyValue(contextInfo) && - (token.startsWith('#') || token.startsWith('$'))) { - contextInfo = getContext({ - columnName - }) // get global context - } - // menu attribute isEmptyValue isSOTrx - if (!isEmptyValue(isSOTrxMenu) && token === 'IsSOTrx' && isEmptyValue(contextInfo)) { - contextInfo = isSOTrxMenu - if (isBooleanToString || isSQL) { - contextInfo = convertBooleanToString(contextInfo) - } - } if (contextInfo === undefined || contextInfo.length === 0) { // console.info(`No Context for: ${token}`) isError = true @@ -153,7 +244,8 @@ export function parseContext({ inString = inString.substring(secondIndexTag + 1, inString.length) // from second @ firstIndexTag = inString.indexOf('@') - } + } // end while loop + if (!['object', 'boolean'].includes(typeof contextInfo)) { outString = outString + inString // add the rest of the string } @@ -173,67 +265,3 @@ export function parseContext({ value: outString } } // parseContext - -/** - * Get Preference. - *
- *      0)  Current Setting
- *      1)  Window Preference
- *      2)  Global Preference
- *      3)  Login settings
- *      4)  Accounting settings
- *  
- * @param {string} parentUuid UUID Window - * @param {string} containerUuid UUID Tab, Process, SmartBrowser, Report and Form - * @param {string} columnName (context) Entity to search - * @return preference value - */ -export function getPreference({ - parentUuid, - containerUuid, - columnName -}) { - let retValue - if (isEmptyValue(columnName)) { - console.warn('Require Context ColumnName') - return retValue - } - - // USER PREFERENCES - // View Preferences - if (parentUuid && containerUuid) { - retValue = getContext({ - parentUuid: 'P' + parentUuid, - containerUuid, - columnName: columnName - }) - if (!isEmptyValue(retValue)) { - return retValue - } - } - - // Global Preferences - retValue = getContext({ - columnName: 'P|' + columnName - }) - if (!isEmptyValue(retValue)) { - return retValue - } - - // SYSTEM PREFERENCES - // Login setting - // get # globals context only window - retValue = getContext({ - columnName: '#' + columnName - }) - if (!isEmptyValue(retValue)) { - return retValue - } - - // Accounting setting - retValue = getContext({ - columnName: '$' + columnName - }) - - return retValue -} // getPreference diff --git a/src/utils/ADempiere/dictionaryUtils.js b/src/utils/ADempiere/dictionaryUtils.js index 2bcfab7f..8c078dd3 100644 --- a/src/utils/ADempiere/dictionaryUtils.js +++ b/src/utils/ADempiere/dictionaryUtils.js @@ -63,7 +63,7 @@ export function generateField({ ...moreAttributes, columnName: fieldToGenerate.columnName, value: parsedDefaultValue, - isSOTrxMenu: isSOTrxMenu + isSOTrxMenu }).value } @@ -88,7 +88,8 @@ export function generateField({ } parsedDefaultValue = parsedValueComponent({ - fieldType: componentReference.componentPath, + componentPath: componentReference.componentPath, + columnName: fieldToGenerate.columnName, value: parsedDefaultValue, displayType: fieldToGenerate.displayType, isMandatory: fieldToGenerate.isMandatory, @@ -132,7 +133,8 @@ export function generateField({ } parsedDefaultValueTo = parsedValueComponent({ - fieldType: componentReference.componentPath, + componentPath: componentReference.componentPath, + columnName: fieldToGenerate.columnName, value: parsedDefaultValueTo, displayType: fieldToGenerate.displayType, isMandatory: fieldToGenerate.isMandatory, @@ -170,12 +172,15 @@ export function generateField({ const field = { ...fieldToGenerate, ...moreAttributes, + columnNameTo: undefined, + elementNameTo: undefined, isSOTrxMenu, // displayed attributes componentPath: componentReference.componentPath, isSupported: componentReference.isSupported, size: componentReference.size || DEFAULT_SIZE, displayColumn: undefined, // link to value from selects and table + displayColumnName: `DisplayColumn_${fieldToGenerate.columnName}`, // key to display column // value attributes value: String(parsedDefaultValue).trim() === '' ? undefined : parsedDefaultValue, oldValue: parsedDefaultValue, @@ -211,9 +216,12 @@ export function generateField({ // Overwrite some values if (field.isRange) { field.operator = 'GREATER_EQUAL' + field.columnNameTo = `${field.columnName}_To` + field.elementNameTo = `${field.elementNameTo}_To` if (typeRange) { field.uuid = `${field.uuid}_To` - field.columnName = `${field.columnName}_To` + field.columnName = field.columnNameTo + field.elementName = field.elementNameTo field.name = `${field.name} To` field.value = parsedDefaultValueTo field.defaultValue = field.defaultValueTo @@ -491,24 +499,32 @@ export function sortFields({ /** * Determinate if field is displayed - * @param {boolean} field.isActive - * @param {boolean} field.isDisplayed - * @param {boolean} field.isDisplayedFromLogic - * @param {boolean} field.isQueryCriteria - * @param {string} field.panelType + * @param {boolean} isActive + * @param {boolean} isDisplayed + * @param {boolean} isDisplayedFromLogic + * @param {boolean} isQueryCriteria + * @param {string} panelType * @returns {boolean} */ -export function fieldIsDisplayed(field) { - // if is Advanced Query - if (field.panelType === 'table') { - return field.isDisplayed && field.isDisplayedFromLogic +export function fieldIsDisplayed({ + panelType, + isActive, + isDisplayed, + isDisplayedFromLogic, + isQueryCriteria +}) { + // Verify if field is active + if (!isActive) { + return false } - const isBrowserDisplayed = field.isQueryCriteria // browser query criteria - const isWindowDisplayed = field.isDisplayed && field.isDisplayedFromLogic // window, process and report, browser result - const isDisplayedView = (field.panelType === 'browser' && isBrowserDisplayed) || (field.panelType !== 'browser' && isWindowDisplayed) - // Verify for displayed and is active - return field.isActive && isDisplayedView + // browser query criteria + if (panelType === 'browser') { + return isQueryCriteria + } + + // window, table (advanced query), process and report, browser (table) result + return isDisplayed && isDisplayedFromLogic } // Convert action to action name for route diff --git a/src/utils/ADempiere/evaluator.js b/src/utils/ADempiere/evaluator.js index e7d3c7b9..6d4b2125 100644 --- a/src/utils/ADempiere/evaluator.js +++ b/src/utils/ADempiere/evaluator.js @@ -1,3 +1,6 @@ +import { convertStringToBoolean } from '@/utils/ADempiere/valueFormat.js' +import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js' + // This class is used for evaluate a conditional // format := {expression} [{logic} {expression}]
// expression := @{context}@{operand}{value} or @{context}@{operand}{value}
@@ -27,7 +30,7 @@ class evaluator { defaultReturned = false }) { // empty logic - if (logic === undefined || logic === null || logic.trim() === '') { + if (isEmptyValue(logic)) { return defaultReturned } const st = logic.trim().replace('\n', '') @@ -96,7 +99,7 @@ class evaluator { logic }) { // not context info, not logic - if (logic === undefined || logic === null || logic.trim() === '') { + if (isEmptyValue(logic)) { return defaultReturned } @@ -140,14 +143,14 @@ class evaluator { columnName: first }) // in context exists this column name - if (value === null || value === undefined) { - // console.info(`.The column ${first} not exists in context.`) + if (isEmptyValue(value)) { + // console.info(`.The column ${first} not exists in context.`) return defaultReturned } firstEval = value // replace with it's value } - if (firstEval === null || firstEval === undefined) { + if (isEmptyValue(firstEval)) { return defaultReturned } if (typeof firstEval === 'string') { @@ -193,16 +196,6 @@ class evaluator { * @return {boolean} */ static evaluateLogicTuple(value1, operand, value2) { - const convertStringToBoolean = (valueToParsed) => { - const valueString = String(valueToParsed).trim() - if (valueString === 'Y') { - return true - } else if (valueString === 'N') { - return false - } - return valueToParsed - } - // Convert value 1 string value to boolean value value1 = convertStringToBoolean(value1) @@ -250,7 +243,7 @@ class evaluator { */ static parseDepends(parseString) { const listFields = [] - if (parseString === null || parseString === undefined) { + if (isEmptyValue(parseString)) { // return array empty return listFields } diff --git a/src/utils/ADempiere/lookupFactory.js b/src/utils/ADempiere/lookupFactory.js index 097ef807..591b0792 100644 --- a/src/utils/ADempiere/lookupFactory.js +++ b/src/utils/ADempiere/lookupFactory.js @@ -285,6 +285,7 @@ export function getFieldTemplate(overwriteDefinition) { isKey: false, isSelectionColumn: false, isUpdateable: true, + // formatPattern: undefined, VFormat: undefined, value: undefined, @@ -293,6 +294,7 @@ export function getFieldTemplate(overwriteDefinition) { parsedDefaultValue: undefined, defaultValueTo: undefined, parsedDefaultValueTo: undefined, + valueType: componentReference.valueType, // value type to convert with gGRPC valueMin: undefined, valueMax: undefined, // diff --git a/src/utils/ADempiere/valueFormat.js b/src/utils/ADempiere/valueFormat.js index 8a7fda16..4688a32b 100644 --- a/src/utils/ADempiere/valueFormat.js +++ b/src/utils/ADempiere/valueFormat.js @@ -1,10 +1,90 @@ // A util class for handle format for time, date and others values to beused to display information // Note that this file use moment library for a easy conversion import moment from 'moment' -import { isEmptyValue } from '@/utils/ADempiere/valueUtils' +import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js' import store from '@/store' import { DATE, DATE_PLUS_TIME, TIME } from '@/utils/ADempiere/references' +export const convertStringToBoolean = (valueToParsed) => { + const valueString = String(valueToParsed).trim() + if (valueString === 'N' || valueString === 'false') { + return false + } + return Boolean(valueToParsed) +} + +export const convertBooleanToString = (booleanValue) => { + if (booleanValue || booleanValue === 'true') { + return 'Y' + } + return 'N' +} + +/** + * Convert a object to array pairs + * @param {object} object, object to convert + * @param {string} nameKey, name from key in pairs + * @param {string} nameValue, name from value in pairs + * @returns {array} [ { nameKey: key, nameValue: value } ] + */ +export function convertObjectToKeyValue({ + object, + keyName = 'columnName', + valueName = 'value' +}) { + return Object.keys(object).map(key => { + const returnPairs = {} + returnPairs[keyName] = key + returnPairs[valueName] = object[key] + return returnPairs + }) +} + +/** + * Convert array pairs of object to literal object { key: value } + * @param {array} array, Array to convert + * @param {string} nameKey, name from key in pairs + * @param {string} nameValue, name from value in pairs + * @returns {object} { key: value, key2: value2 } + */ +export function convertArrayKeyValueObject({ + array, + keyName = 'columnName', + valueName = 'value' +}) { + const result = {} + array.forEach(element => { + result[element[keyName]] = element[valueName] + }) + + return result +} + +/** + * Convert map of pairs to literal object + * @param {object} object + * @returns {map} + */ +export function convertObjectToHasMap({ object }) { + return new Map( + Object.entries(object) + ) +} + +/** + * Convert map of pairs to literal object + * @param {map} hasMapToConvert + * @returns {object} { key: value, key2: value2 } + */ +export function convertHasMapToObject({ map }) { + return Object.fromEntries(map) + // const result = {} + // map.forEach((value, key) => { + // result[key] = value + // }) + // return result +} + // This function just convert all java date format to moment format. // For know about java format pattern see: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html // Also you can read moment docus: https://momentjs.com/docs/ diff --git a/src/utils/ADempiere/valueUtils.js b/src/utils/ADempiere/valueUtils.js index 1a511029..9dbf8d85 100644 --- a/src/utils/ADempiere/valueUtils.js +++ b/src/utils/ADempiere/valueUtils.js @@ -1,4 +1,5 @@ -import { TABLE, TABLE_DIRECT } from '@/utils/ADempiere/references' +import { convertStringToBoolean, convertBooleanToString } from '@/utils/ADempiere/valueFormat.js' +import { TABLE, TABLE_DIRECT } from '@/utils/ADempiere/references.js' /** * Checks if value is empty. Deep-checks arrays and objects @@ -87,49 +88,6 @@ export function clientDateTime(date = null, type = '') { return currentDateTime.date + ' ' + currentDateTime.time } -/** - * Convert a object to array pairs - * @param {object} objectToConvert, object to convert - * @param {string} nameKey, name from key in pairs - * @param {string} nameValue, name from value in pairs - * @returns {array} [ { nameKey: key, nameValue: value } ] - */ -export function convertObjectToArrayPairs(objectToConvert, nameKey = 'columnName', nameValue = 'value') { - return Object.keys(objectToConvert).map(key => { - const returnPairs = {} - returnPairs[nameKey] = key - returnPairs[nameValue] = objectToConvert[key] - return returnPairs - }) -} - -/** - * Convert array pairs of object to simple object { key:value } - * @param {array} arrayToConvert, object to convert - * @param {string} nameKey, name from key in pairs - * @param {string} nameValue, name from value in pairs - */ -export function convertArrayPairsToObject({ - arrayToConvert, - nameKey = 'columnName', - nameValue = 'value' -}) { - const result = {} - arrayToConvert.forEach(element => { - result[element[nameKey]] = element[nameValue] - }) - - return result -} - -export function convertHasMapToObject(hasMapToConvert) { - const result = {} - hasMapToConvert.forEach((value, key) => { - result[key] = value - }) - return result -} - export function convertFieldListToShareLink(fieldList) { var attributesListLink = '' fieldList.map(fieldItem => { @@ -230,28 +188,33 @@ export const recursiveTreeSearch = ({ /** * Parsed value to component type * @param {mixed} value, value to parsed - * @param {string} fieldType, or componentPath + * @param {string} componentPath * @param {number} displayType, reference in ADempiere * @param {boolean} isMandatory, field is mandatory * @param {boolean} isIdentifier, field is ID */ export function parsedValueComponent({ - fieldType, + componentPath, value, + columnName, displayType, isMandatory = false, isIdentifier = false }) { const isEmpty = isEmptyValue(value) if (isEmpty && !isMandatory) { - if (fieldType === 'FieldYesNo') { + if (componentPath === 'FieldYesNo') { + if (columnName === 'IsActive') { + return true + } + // Processing, Processed, and any other columnName, return false by default return Boolean(value) } return undefined } var returnValue - switch (fieldType) { + switch (componentPath) { // data type Number case 'FieldNumber': if (isEmpty) { @@ -272,12 +235,10 @@ export function parsedValueComponent({ // data type Boolean case 'FieldYesNo': - if (value === 'false' || value === 'N') { - value = false - } else if (typeof value === 'object' && Object.prototype.hasOwnProperty.call(value, 'query')) { + if (typeof value === 'object' && Object.prototype.hasOwnProperty.call(value, 'query')) { returnValue = value } - returnValue = Boolean(value) + returnValue = convertStringToBoolean(value) break // data type String @@ -312,7 +273,7 @@ export function parsedValueComponent({ value = undefined } if (typeof value === 'boolean') { - value = value ? 'Y' : 'N' + value = convertBooleanToString(value) } // Table (18) or Table Direct (19) if (displayType === TABLE_DIRECT.id || (displayType === TABLE.id && isIdentifier)) { diff --git a/src/views/ADempiere/Browser/index.vue b/src/views/ADempiere/Browser/index.vue index fdf71980..27280eee 100644 --- a/src/views/ADempiere/Browser/index.vue +++ b/src/views/ADempiere/Browser/index.vue @@ -117,8 +117,11 @@ export default { isLoadedRecords() { return this.$store.getters.getDataRecordAndSelection(this.browserUuid).isLoaded }, - getContainerIsReadyForSubmit() { - return !this.$store.getters.isNotReadyForSubmit(this.browserUuid) && !this.browserMetadata.awaitForValuesToQuery + isReadyToSearch() { + if (this.browserMetadata.awaitForValuesToQuery) { + return false + } + return !this.$store.getters.isNotReadyForSubmit(this.browserUuid) }, isMobile() { return this.$store.state.app.device === 'mobile' @@ -136,19 +139,15 @@ export default { return 'content-help' }, isShowedCriteria() { - if (this.getterBrowser) { - return this.getterBrowser.isShowedCriteria + if (this.browserMetadata) { + return this.browserMetadata.isShowedCriteria } return false } }, watch: { isShowedCriteria(value) { - const activeSearch = [] - if (value) { - activeSearch.push('opened-criteria') - } - this.activeSearch = activeSearch + this.handleCollapse(value) } }, created() { @@ -166,6 +165,18 @@ export default { attributeValue: showCriteria }) }, + /** + * Manage open or closed component collapse of criteria + */ + handleCollapse(isShowedCriteria) { + // by default criteria if closed + const activeSearch = [] + if (isShowedCriteria) { + // open criteria + activeSearch.push('opened-criteria') + } + this.activeSearch = activeSearch + }, getBrowser() { const browser = this.getterBrowser if (browser) { @@ -181,6 +192,7 @@ export default { }) .then(browserResponse => { this.browserMetadata = browserResponse + this.handleCollapse(browserResponse.isShowedCriteria) this.defaultSearch() }) .finally(() => { @@ -188,24 +200,23 @@ export default { }) }, defaultSearch() { - // open or closed show criteria - this.activeSearch = [] - if (this.browserMetadata.isShowedCriteria) { - this.activeSearch = ['opened-criteria'] - } - - if (!this.isLoadedRecords) { - if (this.getContainerIsReadyForSubmit) { + if (this.isLoadedRecords) { + // not research + return + } else { + if (this.isReadyToSearch) { + // first search by default this.$store.dispatch('getBrowserSearch', { containerUuid: this.browserUuid }) + return } - } else { - this.$store.dispatch('setRecordSelection', { - containerUuid: this.browserUuid, - panelType: this.panelType - }) } + // set default values into data + this.$store.dispatch('setRecordSelection', { + containerUuid: this.browserUuid, + panelType: this.panelType + }) } } }