1
0
mirror of https://github.com/PanJiaChen/vue-element-admin.git synced 2025-08-12 22:29:59 +08:00

Add API REST support based on proxy-adempiere-api and backend implementation (#529)

This commit is contained in:
Yamel Senih 2020-10-28 17:19:53 -04:00 committed by GitHub
parent 62742995a2
commit 6e54d93b9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
202 changed files with 16030 additions and 6156 deletions

View File

@ -39,7 +39,7 @@ Este es una gran UI para [ADempiere ERP, CRM & SCM](https://github.com/adempiere
- [Canal de Gitter](https://gitter.im/adempiere/adempiere-vue) - [Canal de Gitter](https://gitter.im/adempiere/adempiere-vue)
- [Para Donaciones](https://www.paypal.me/?) - [Para Donaciones](https://www.paypal.me/YamelSenih)
- [Enlace de Wiki](http://wiki.adempiere.net/ADempiere_ERP) - [Enlace de Wiki](http://wiki.adempiere.net/ADempiere_ERP)
@ -129,6 +129,7 @@ Sea un patrocinante y coloque su logo en nuestro LEEME en GitHub con un enlace d
- Componente para soltar archivos - Componente para soltar archivos
- Adhesión de objetos - Adhesión de objetos
- Contador hasta - Contador hasta
- Soporte a ADempiere - Soporte a ADempiere
- Ventana - Ventana
- Proceso - Proceso
@ -205,7 +206,7 @@ Los cambios detallados por cada liberación se encuentran en [notas de liberaci
Si este proyecto es de mucha ayuda para ti, puedes ayudar a hacer una mejor UI Si este proyecto es de mucha ayuda para ti, puedes ayudar a hacer una mejor UI
[dona por Paypal](https://www.paypal.me/?) [dona por Paypal](https://www.paypal.me/YamelSenih)
## Navegadores Soportados ## Navegadores Soportados

View File

@ -62,12 +62,12 @@ Understanding and learning this knowledge in advance will greatly help the use o
## Sponsors ## Sponsors
<a href="https://erpya.com/"><img width="250px" src="https://i0.wp.com/spin-suite.com/erpya/wp-content/uploads/sites/28/2017/11/ERP-logotipo-H-color.png" /></a> <a href="http://erpya.com/"><img width="250px" src="https://i0.wp.com/spin-suite.com/erpya/wp-content/uploads/sites/28/2017/11/ERP-logotipo-H-color.png" /></a>
<a href="http://www.e-evolution.com/"><img width="250px" src="https://i0.wp.com/mysmart.business/evolution/wp-content/uploads/sites/29/2017/10/e-evolution-logo-v2.png?fit=150%2C92" /></a> <a href="http://www.e-evolution.com/"><img width="250px" src="https://i0.wp.com/mysmart.business/evolution/wp-content/uploads/sites/29/2017/10/e-evolution-logo-v2.png?fit=150%2C92" /></a>
<a href="http://westfalia-it.com/"><img width="150px" src="https://i1.wp.com/spin-suite.com/westfalia/wp-content/uploads/sites/30/2017/12/logo_copy.jpg?fit=265%2C357" /></a> <a href="http://westfalia-it.com/"><img width="150px" src="https://i1.wp.com/spin-suite.com/westfalia/wp-content/uploads/sites/30/2017/12/logo_copy.jpg?fit=265%2C357" /></a>
<a href="http://openupsolutions.com/"><img width="250px" src="https://i0.wp.com/spin-suite.com/openupsolutions/wp-content/uploads/sites/32/2017/05/Openup-Solutions-Logo-2017-80x200px.png" /></a> <a href="http://openupsolutions.com/"><img width="250px" src="https://i0.wp.com/spin-suite.com/openupsolutions/wp-content/uploads/sites/32/2017/05/Openup-Solutions-Logo-2017-80x200px.png" /></a>
Become a sponsor and get your logo on our README on GitHub with a link to your site. [Become a sponsor](https://www.paypal.me/?) Become a sponsor and get your logo on our README on GitHub with a link to your site. [Become a sponsor](https://www.paypal.me/YamelSenih)
## Features ## Features
@ -129,6 +129,7 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- Dropzone - Dropzone
- Sticky - Sticky
- CountTo - CountTo
- ADempiere supported - ADempiere supported
- Window - Window
- Process - Process
@ -204,7 +205,7 @@ Detailed changes for each release are documented in the [release notes](https://
If you find this project useful, you can help this make a better UI If you find this project useful, you can help this make a better UI
[Paypal Me](https://www.paypal.me/?) [Paypal Me](https://www.paypal.me/YamelSenih)
## Browsers support ## Browsers support

View File

@ -22,12 +22,7 @@
"test:ci": "npm run lint && npm run test:unit" "test:ci": "npm run lint && npm run test:unit"
}, },
"dependencies": { "dependencies": {
"@adempiere/grpc-access-client": "^1.2.3", "@toast-ui/vue-editor": "^2.4.0",
"@adempiere/grpc-core-client": "^1.2.4",
"@adempiere/grpc-data-client": "^2.4.9",
"@adempiere/grpc-dictionary-client": "^1.4.5",
"@adempiere/grpc-enrollment-client": "^1.1.2",
"@adempiere/grpc-pos-client": "^1.4.1",
"axios": "0.19.2", "axios": "0.19.2",
"clipboard": "2.0.6", "clipboard": "2.0.6",
"codemirror": "5.56.0", "codemirror": "5.56.0",
@ -57,7 +52,7 @@
"vue-i18n": "8.19.0", "vue-i18n": "8.19.0",
"vue-multipane": "^0.9.5", "vue-multipane": "^0.9.5",
"vue-resize": "^0.5.0", "vue-resize": "^0.5.0",
"vue-router": "3.3.4", "vue-router": "3.4.3",
"vue-shortkey": "^3.1.7", "vue-shortkey": "^3.1.7",
"vue-split-panel": "^1.0.4", "vue-split-panel": "^1.0.4",
"vue-splitpane": "1.0.6", "vue-splitpane": "1.0.6",
@ -68,6 +63,7 @@
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "4.4.6", "@vue/cli-plugin-babel": "4.4.6",
"@vue/cli-plugin-eslint": "4.4.6", "@vue/cli-plugin-eslint": "4.4.6",
"@vue/cli-plugin-pwa": "4.5.6",
"@vue/cli-plugin-unit-jest": "4.4.6", "@vue/cli-plugin-unit-jest": "4.4.6",
"@vue/cli-service": "4.4.6", "@vue/cli-service": "4.4.6",
"@vue/test-utils": "1.0.3", "@vue/test-utils": "1.0.3",
@ -80,6 +76,7 @@
"connect": "3.7.0", "connect": "3.7.0",
"eslint": "7.5.0", "eslint": "7.5.0",
"eslint-plugin-vue": "6.2.2", "eslint-plugin-vue": "6.2.2",
"fs": "0.0.1-security",
"html-webpack-plugin": "4.3.0", "html-webpack-plugin": "4.3.0",
"husky": "4.2.5", "husky": "4.2.5",
"lint-staged": "10.2.11", "lint-staged": "10.2.11",

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 B

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<link rel="manifest" href="<%= BASE_URL %>manifest.json">
<meta name="renderer" content="webkit"> <meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico">
@ -11,5 +12,16 @@
<body> <body>
<div id="app"></div> <div id="app"></div>
<!-- built files will be auto injected --> <!-- built files will be auto injected -->
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('<%= htmlWebpackPlugin.options.pwaPath %>sw.js').then(function(registration) {
// Registration Success
console.log('[serviceWorker]: registration successful with scope: ', registration.scope)
}).catch(function(err) {
// Registration failed :(
console.log('[serviceWorker] registration failed', err)
})
}
</script>
</body> </body>
</html> </html>

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

15
public/manifest.json Normal file
View File

@ -0,0 +1,15 @@
{
"name": "ADempiere-Vue",
"short_name": "AD-Vue",
"icons": [
{
"src": "./logo.png",
"sizes": "200x200",
"type": "image/png"
}
],
"start_url": "/adempiere-vue/",
"display": "standalone",
"background_color": "#2d3a4b",
"theme_color": "#3d5165"
}

View File

@ -1,28 +1,69 @@
// Get Instance for connection // Get Instance for connection
import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
/** /**
* Request a browser search * Request a browser search
* @param {string} uuid * @param {string} uuid
* @param {string} query * @param {string} tableName
* @param {string} whereClause
* @param {string} orderByClause
* @param {string} nextPageToken
* @param {array} parametersList, This allows follow structure: * @param {array} parametersList, This allows follow structure:
* [{ * [{
* columnName, * columnName,
* value * key
* }] * }]
* @param {array} filters
* @param {array} columns
* @param {string} query
* @param {string} whereClause
* @param {number} limit
* @param {string} orderByClause
* @param {string} nextPageToken
*/ */
export function getBrowserSearch({ uuid, parametersList = [], query, whereClause, orderByClause, nextPageToken: pageToken, pageSize }) { export function requestBrowserSearch({
// Run browser
return Instance.call(this).requestListBrowserSearch({
uuid, uuid,
parametersList, parametersList = [],
tableName,
query, query,
whereClause, whereClause,
orderByClause, orderByClause,
pageToken, limit,
nextPageToken: pageToken,
pageSize pageSize
}) {
const filters = parametersList.map(parameter => {
return {
key: parameter.columnName,
value: parameter.value,
values: parameter.values
}
})
return requestRest({
url: '/ui/list-browser-items',
data: {
// Running Parameters
uuid,
table_name: tableName,
// DSL Query
filters,
// Custom Query
query,
where_clause: whereClause,
order_by_clause: orderByClause,
limit
},
params: {
// Page Data
page_token: pageToken,
page_size: pageSize
}
})
.then(evaluateResponse)
.then(responseBrowserSearch => {
const { convertEntityList } = require('@/utils/ADempiere/apiConverts/persistence.js')
return convertEntityList(responseBrowserSearch)
}) })
} }

View File

@ -1,13 +1,5 @@
const proxyAddress = process.env.VUE_APP_PROXY_ADDRESS || 'localhost' const apiRestAddress = process.env.VUE_APP_API_REST_ADDRESS || '0.0.0.0'
const proxyPort = process.env.VUE_APP_PROXY_PORT || '8989' const apiRestPort = process.env.VUE_APP_API_REST_PORT || '8085'
export const API_ADDRESS = `http://${proxyAddress}:${proxyPort}` export const API_REST_ADDRESS = `http://${apiRestAddress}:${apiRestPort}/adempiere-api`
export const ACCESS_ADDRESS = `${API_ADDRESS}/access`
export const DICTIONARY_ADDRESS = `${API_ADDRESS}/dictionary`
export const BUSINESS_DATA_ADDRESS = `${API_ADDRESS}/businessdata`
export const ENROLLMENT_ADDRESS = `${API_ADDRESS}/enrollment`

View File

@ -2,36 +2,141 @@
// please if you want to implement a custom dashboard create a new fielwith api definition // please if you want to implement a custom dashboard create a new fielwith api definition
// Get Instance for connection // Get Instance for connection
import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
// Get Recent Items based on selection option // Get Recent Items based on selection option
export function getRecentItems({ pageToken, pageSize }) { export function requestListRecentItems({
return Instance.call(this).requestListRecentItems({ pageToken, pageSize }) userUuid,
roleUuid,
pageToken,
pageSize
}) {
return requestRest({
url: '/logs/list-recent-items',
data: {
user_uuid: userUuid,
role_uuid: roleUuid,
current_session: true
},
params: {
// Page Data
pageToken,
pageSize
}
})
.then(evaluateResponse)
.then(recentItmesReponse => {
const { convertRecentItemsList } = require('@/utils/ADempiere/apiConverts/dashboard.js')
return convertRecentItemsList(recentItmesReponse)
})
} }
/** /**
* Request Favorites List * Request Favorites List
* @param {string} userUuid * @param {string} userUuid
*/ */
export function getFavoritesFromServer({ userUuid, pageToken, pageSize }) { export function getFavoritesFromServer({
return Instance.call(this).requestListFavorites({ userUuid, pageToken, pageSize }) userId,
userUuid,
pageToken,
pageSize
}) {
return requestRest({
url: '/dashboard/list-favorites',
data: {
user_id: userId,
user_uuid: userUuid
},
params: {
// Page Data
pageToken,
pageSize
}
})
.then(evaluateResponse)
.then(favoritesListReponse => {
const { convertFavorite } = require('@/utils/ADempiere/apiConverts/dashboard.js')
return {
recordCount: favoritesListReponse.record_count,
favoritesList: favoritesListReponse.records.map(favorite => {
return convertFavorite(favorite)
}),
nextPageToken: favoritesListReponse.next_page_token
}
})
} }
// Get pending documents // Get pending documents
export function getPendingDocumentsFromServer({ userUuid, roleUuid, pageToken, pageSize }) { export function getPendingDocumentsFromServer({
return Instance.call(this).requestListPendingDocuments({ userId,
userUuid, userUuid,
roleId,
roleUuid, roleUuid,
pageToken, pageToken,
pageSize pageSize
}) {
return requestRest({
url: '/dashboard/list-pending-documents',
data: {
user_id: userId,
user_uuid: userUuid,
role_id: roleId,
role_uuid: roleUuid
},
params: {
// Page Data
pageToken,
pageSize
}
})
.then(evaluateResponse)
.then(pendingDocumentsListResponse => {
const { convertPendingDocument } = require('@/utils/ADempiere/apiConverts/dashboard.js')
return {
recordCount: pendingDocumentsListResponse.record_count,
pendingDocumentsList: pendingDocumentsListResponse.records.map(pendingDocument => {
return convertPendingDocument(pendingDocument)
}),
nextPageToken: pendingDocumentsListResponse.next_page_token
}
}) })
} }
// List all dashboard for role // List all dashboard for role
export function requestLisDashboards({ roleUuid, pageToken, pageSize }) { export function requestLisDashboards({
return Instance.call(this).requestListDashboards({ roleId,
roleUuid, roleUuid,
pageToken, pageToken,
pageSize pageSize
}) {
return requestRest({
url: '/dashboard/list-dashboards',
data: {
role_id: roleId,
role_uuid: roleUuid
},
params: {
// Page Data
pageToken,
pageSize
}
})
.then(evaluateResponse)
.then(dashboardsListResponse => {
const { convertDashboard } = require('@/utils/ADempiere/apiConverts/dashboard.js')
return {
recordCount: dashboardsListResponse.record_count,
dashboardsList: dashboardsListResponse.records.map(favorite => {
return convertDashboard(favorite)
}),
nextPageToken: dashboardsListResponse.next_page_token
}
}) })
} }

View File

@ -1,78 +1,177 @@
// Get Instance for connection // Get Instance for connection
import { DictionaryInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
export function getWindow({ uuid, id, isWithTabs = true }) { /**
return Instance.call(this).requestWindow({ * Request dictionary Window metadata
uuid, * @param {string} uuid universally unique identifier
id, * @param {number} id, identifier
isWithTabs */
}) export function requestWindowMetadata({
}
export function getProcess({ uuid, id }) {
return Instance.call(this).requestProcess({
uuid,
id,
isWithFields: true
})
}
export function getBrowser({ uuid, id }) {
return Instance.call(this).requestBrowser({
uuid, uuid,
id id
}) }) {
} return requestRest({
url: '/dictionary/window',
export function getTab({ uuid, id, isWithFields = true }) { method: 'get',
return Instance.call(this).requestTab({ params: {
uuid, uuid,
id, id
isWithFields }
})
.then(evaluateResponse)
.then(windowResponse => {
const { convertWindow } = require('@/utils/ADempiere/apiConverts/dictionary.js')
return convertWindow(windowResponse)
}) })
} }
export function getField({ /**
fieldUuid, * Request dictionary Process/Report metadata
* @param {string} uuid universally unique identifier
* @param {number} id, identifier
*/
export function requestProcessMetadata({
uuid,
id
}) {
return requestRest({
url: '/dictionary/process',
method: 'get',
params: {
uuid,
id
}
})
.then(evaluateResponse)
.then(processResponse => {
const { convertProcess } = require('@/utils/ADempiere/apiConverts/dictionary.js')
return convertProcess(processResponse)
})
}
/**
* Request dictionary Smart Browser metadata
* @param {string} uuid universally unique identifier
* @param {number} id, identifier
*/
export function requestBrowserMetadata({
uuid,
id
}) {
return requestRest({
url: '/dictionary/browser',
method: 'get',
params: {
uuid,
id
}
})
.then(evaluateResponse)
.then(browserResponse => {
const { convertBrowser } = require('@/utils/ADempiere/apiConverts/dictionary.js')
return convertBrowser(browserResponse)
})
}
/**
* Request dictionary Form metadata
* @param {string} uuid universally unique identifier
* @param {number} id, integer identifier
*/
export function requestForm({
uuid,
id
}) {
return requestRest({
url: '/dictionary/form',
method: 'get',
params: {
uuid,
id
}
})
.then(evaluateResponse)
.then(formResponse => {
const { convertForm } = require('@/utils/ADempiere/apiConverts/dictionary.js')
return convertForm(formResponse)
})
}
export function requestFieldMetadata({
uuid,
columnUuid, columnUuid,
elementUuid, elementUuid,
fieldUuid,
// TableName + ColumnName // TableName + ColumnName
tableName, tableName,
columnName, columnName,
elementColumnName elementColumnName
}) { }) {
return Instance.call(this).requestField({ return requestRest({
fieldUuid, url: '/dictionary/field',
columnUuid, method: 'get',
elementUuid, params: {
uuid,
column_uuid: columnUuid,
element_uuid: elementUuid,
field_uuid: fieldUuid,
// TableName + ColumnName // TableName + ColumnName
tableName, table_name: tableName,
columnName, column_name: columnName,
elementColumnName element_column_name: elementColumnName
}
})
.then(evaluateResponse)
.then(fieldResponse => {
const { convertField } = require('@/utils/ADempiere/apiConverts/field.js')
return convertField(fieldResponse)
}) })
} }
/** export function requestReference({
* Request Form uuid,
* @param {string} uuid columnName
* @param {number} id, integer identifier }) {
*/ return requestRest({
export function requestForm({ uuid, id }) { url: '/dictionary/reference',
return Instance.call(this).requestForm({ method: 'get',
params: {
uuid,
column_name: columnName
}
})
.then(evaluateResponse)
.then(validationResponse => {
const { convertReference } = require('@/utils/ADempiere/apiConverts/field.js')
return convertReference(validationResponse)
})
}
export function requestValidationRule({
uuid,
id
}) {
return requestRest({
url: '/dictionary/validation',
method: 'get',
params: {
uuid, uuid,
id id
})
} }
})
.then(evaluateResponse)
.then(validationResponse => {
const { convertValidationRule } = require('@/utils/ADempiere/apiConverts/dictionary.js')
export function requestReference({ referenceUuid, columnName }) { return convertValidationRule(validationResponse)
return Instance.call(this).requestReference({
referenceUuid,
columnName
})
}
export function requestValidationRule({ validationRuleUuid }) {
return Instance.call(this).requestValidationRule({
validationRuleUuid
}) })
} }

View File

@ -1,5 +1,11 @@
// Get Instance for connection // Get Instance for connection
import { EnrollmentInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
const clientVersion = '1.0.0'
const applicationType = 'ADempiere-Vue'
/** /**
* enroll User * enroll User
@ -7,12 +13,30 @@ import { EnrollmentInstance as Instance } from '@/api/ADempiere/instances.js'
* @param {string} userData.userName * @param {string} userData.userName
* @param {string} userData.password * @param {string} userData.password
*/ */
export function enrollmentUser({ name, userName, password, eMail }) { export function requestEnrollUser({
return Instance.call(this).enrollUser({
name, name,
userName, userName,
password, password,
eMail eMail
}) {
return requestRest({
url: '/enrollment/enroll',
data: {
user_name: userName,
name,
email: eMail,
password,
client_version: clientVersion,
application_type: applicationType
}
})
.then(evaluateResponse)
.then(enrollResponse => {
return {
userName: enrollResponse.user_name,
name: enrollResponse.name,
eMail: enrollResponse.email
}
}) })
} }
@ -20,8 +44,30 @@ export function enrollmentUser({ name, userName, password, eMail }) {
* Request from forgot password * Request from forgot password
* @param {string} eMailOrUserName * @param {string} eMailOrUserName
*/ */
export function forgotPassword(eMailOrUserName) { export function requestForgotPassword(eMailOrUserName) {
return Instance.call(this).requestResetPassword(eMailOrUserName) let userName, eMail
if (String(eMailOrUserName).includes('@')) {
eMail = eMailOrUserName
} else {
userName = eMailOrUserName
}
return requestRest({
url: '/enrollment/reset-password',
data: {
user_name: userName,
email: eMail,
client_version: clientVersion,
application_type: applicationType
}
})
.then(evaluateResponse)
.then(forgotResponse => {
return {
responseType: forgotResponse.response_type,
responseTypeStatus: forgotResponse.response_type_status
}
})
} }
/** /**
@ -29,6 +75,49 @@ export function forgotPassword(eMailOrUserName) {
* @param {string} token * @param {string} token
* @param {string} password * @param {string} password
*/ */
export function resetPasswordFromToken({ token, password }) { export function requestChangePassword({
return Instance.call(this).resetPasswordFromToken({ token, password }) token,
password
}) {
return requestRest({
url: '/enrollment/change-password',
data: {
token,
password,
client_version: clientVersion,
application_type: applicationType
}
})
.then(evaluateResponse)
.then(changePasswordResponse => {
return {
responseType: changePasswordResponse.response_type,
responseTypeStatus: changePasswordResponse.response_type_status
}
})
}
/**
* Request from reset password with token
* @param {string} token
* @param {string} password
*/
export function requestActivateUser({
token
}) {
return requestRest({
url: '/enrollment/activate-user',
data: {
token,
client_version: clientVersion,
application_type: applicationType
}
})
.then(evaluateResponse)
.then(activateUserResponse => {
return {
responseType: activateUserResponse.response_type,
responseTypeStatus: activateUserResponse.response_type_status
}
})
} }

View File

@ -2,17 +2,16 @@ const tableName = 'C_Location'
/** /**
* Create a location and return the created entity * Create a location and return the created entity
* @param {array} attributes * @param {array} attributesList
*/ */
export function requestCreateLocationAddress({ export function requestCreateLocationAddress({
attributes attributesList
}) { }) {
const { createEntity } = require('@/api/ADempiere/persistence.js') const { requestCreateEntity } = require('@/api/ADempiere/persistence.js')
return createEntity({ return requestCreateEntity({
tableName, tableName,
attributes, attributesList
formatReturn: 'object'
}) })
} }
@ -25,9 +24,9 @@ export function requestGetLocationAddress({
id, id,
uuid uuid
}) { }) {
const { getEntity } = require('@/api/ADempiere/persistence.js') const { requestGetEntity } = require('@/api/ADempiere/persistence.js')
return getEntity({ return requestGetEntity({
tableName, tableName,
recordId: id, recordId: id,
recordUuid: uuid recordUuid: uuid
@ -38,20 +37,19 @@ export function requestGetLocationAddress({
* Update an existing location by id or uuid * Update an existing location by id or uuid
* @param {number} id as C_Location_ID * @param {number} id as C_Location_ID
* @param {string} uuid * @param {string} uuid
* @param {array} attributes, all attributes (including empty values) * @param {array} attributesList, all attributes (including empty values)
*/ */
export function requestUpdateLocationAddress({ export function requestUpdateLocationAddress({
id, id,
uuid, uuid,
attributes attributesList
}) { }) {
const { updateEntity } = require('@/api/ADempiere/persistence.js') const { requestUpdateEntity } = require('@/api/ADempiere/persistence.js')
return updateEntity({ return requestUpdateEntity({
tableName, tableName,
recordId: id, recordId: id,
recordUuid: uuid, recordUuid: uuid,
attributes, attributesList
formatReturn: 'object'
}) })
} }

View File

@ -1,10 +1,12 @@
export function getLocatorList({ const tableName = 'M_Locator'
export function requestLocatorList({
warehouseId warehouseId
}) { }) {
const { getEntitiesList } = require('@/api/ADempiere/persistence') const { requestListEntities } = require('@/api/ADempiere/persistence.js')
return getEntitiesList({ return requestListEntities({
tableName: 'M_Locator', tableName,
whereClause: `M_Warehouse_ID = ${warehouseId}` whereClause: `M_Warehouse_ID = ${warehouseId}`
}) })
} }

View File

@ -1,78 +1,144 @@
import { POSInstance as Instance } from '@/api/ADempiere/instances.js' // Get Instance for connection
import Criteria from '@/utils/ADempiere/criteria.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
/** /**
* method in price-checking.js as getProductPrice * method in api/price-checking.js as requestGetProductPrice
*/ */
export { getProductPrice as findProduct } from '@/api/ADempiere/form/price-checking.js' export { requestGetProductPrice as findProduct } from '@/api/ADempiere/form/price-checking.js'
export { requestGetConversionRate } from '@/api/ADempiere/system-core.js'
// List Point of sales // List Point of sales
export function requestlistPointOfSales({ export function requestGetPointOfSales({
posUuid
}) {
return requestRest({
url: '/pos/get-point-of-sales',
data: {
point_of_sales_uuid: posUuid
}
})
.then(evaluateResponse)
.then(posResponse => {
const { convertPointOfSales } = require('@/utils/ADempiere/apiConverts/pos.js')
return convertPointOfSales(posResponse)
})
}
// List Point of sales
export function requestListPointOfSales({
userUuid, userUuid,
pageSize, pageSize,
pageToken pageToken
}) { }) {
return Instance.call(this).listPointOfSales({ return requestRest({
userUuid, url: '/pos/list-point-of-sales',
pageSize, data: {
pageToken user_uuid: userUuid
},
params: {
page_size: pageSize,
page_token: pageToken
}
})
.then(evaluateResponse)
.then(posListResponse => {
const { convertPointOfSales } = require('@/utils/ADempiere/apiConverts/pos.js')
return {
nextPageToken: posListResponse.next_page_token,
recordCount: posListResponse.record_count,
sellingPointsList: posListResponse.records.map(pos => {
return convertPointOfSales(pos)
})
}
}) })
} }
// Create order from POS // Create order from POS
export function createOrder({ export function requestCreateOrder({
posUuid, posUuid,
customerUuid, customerUuid,
documentTypeUuid documentTypeUuid,
salesRepresentativeUuid
}) { }) {
return Instance.call(this).createOrder({ return requestRest({
posUuid, url: '/pos/create-order',
customerUuid, data: {
documentTypeUuid pos_uuid: posUuid,
customer_uuid: customerUuid,
document_type_uuid: documentTypeUuid,
sales_representative_uuid: salesRepresentativeUuid
}
})
.then(evaluateResponse)
.then(createOrderResponse => {
const { convertOrder } = require('@/utils/ADempiere/apiConverts/pos.js')
return convertOrder(createOrderResponse)
}) })
} }
// Update order from POS // Update order from POS
export function updateOrder({ export function requestUpdateOrder({
orderUuid, orderUuid,
posUuid, posUuid,
customerUuid, customerUuid,
description description
}) { }) {
return Instance.call(this).updateOrder({ return requestRest({
orderUuid, url: '/pos/update-order',
data: {
order_uuid: orderUuid,
pos_uuid: posUuid,
customer_uuid: customerUuid,
description
}
})
.then(evaluateResponse)
.then(updateOrderResponse => {
const { convertOrder } = require('@/utils/ADempiere/apiConverts/pos.js')
return convertOrder(updateOrderResponse)
})
}
// Get order from uuid
export function requestGetOrder(orderUuid) {
return requestRest({
url: '/pos/update-order',
data: {
order_uuid: orderUuid
}
})
.then(evaluateResponse)
.then(getOrderResponse => {
const { convertOrder } = require('@/utils/ADempiere/apiConverts/pos.js')
return convertOrder(getOrderResponse)
})
}
// Create order from POS
export function requestDeleteOrder({
posUuid, posUuid,
customerUuid, customerUuid,
description documentTypeUuid,
}) salesRepresentativeUuid
}
// Create order line from order uuid and product
export function createOrderLine({
orderUuid,
warehouseUuid,
productUuid,
chargeUuid,
description,
quantity,
price,
discountRate
}) { }) {
return Instance.call(this).createOrderLine({ return requestRest({
orderUuid, url: '/pos/delete-order',
warehouseUuid, data: {
productUuid, pos_uuid: posUuid,
chargeUuid, customer_uuid: customerUuid,
description, document_type_uuid: documentTypeUuid,
quantity, sales_representative_uuid: salesRepresentativeUuid
price,
discountRate
})
} }
})
// Create order line from order uuid and product .then(evaluateResponse)
export function getOrder(orderUuid) {
return Instance.call(this).getOrder({ orderUuid })
} }
// List orders from pos uuid // List orders from pos uuid
@ -92,9 +158,12 @@ export function requestListOrders({
pageSize, pageSize,
pageToken pageToken
}) { }) {
const criteria = new Criteria({ tableName: 'C_Order' })
/* /*
const Criteria = require('@/utils/ADempiere/criteria.js')
const criteria = new Criteria({
tableName: 'C_Order'
})
criteria.addCondition({ criteria.addCondition({
columnName: 'DocumentNo', columnName: 'DocumentNo',
value: documentNo value: documentNo
@ -131,22 +200,70 @@ export function requestListOrders({
}) })
*/ */
return Instance.call(this).listOrders({ return requestRest({
posUuid, url: '/pos/list-orders',
documentNo, data: {
businessPartnerUuid, pos_uuid: posUuid,
grandTotal, document_no: documentNo,
openAmount, business_partner_uuid: businessPartnerUuid,
isPaid, sales_representative_uuid: salesRepresentativeUuid,
isProcessed, grand_total: grandTotal,
isAisleSeller, open_amount: openAmount,
isInvoiced, is_paid: isPaid,
dateOrderedFrom, is_processed: isProcessed,
dateOrderedTo, is_aisle_seller: isAisleSeller,
salesRepresentativeUuid, is_invoiced: isInvoiced,
criteria: criteria.getCriteria(), date_ordered_from: dateOrderedFrom,
pageSize, date_ordered_to: dateOrderedTo
pageToken },
params: {
page_size: pageSize,
page_token: pageToken
}
})
.then(evaluateResponse)
.then(ordersListResponse => {
const { convertOrder } = require('@/utils/ADempiere/apiConverts/core.js')
return {
nextPageToken: ordersListResponse.next_page_token,
recordCount: ordersListResponse.record_count,
ordersList: ordersListResponse.records.map(productPrice => {
return convertOrder(productPrice)
})
}
})
}
// Create order line from order uuid and product
export function requestCreateOrderLine({
orderUuid,
warehouseUuid,
productUuid,
chargeUuid,
description,
quantity,
price,
discountRate
}) {
return requestRest({
url: '/pos/create-order-line',
data: {
order_uuid: orderUuid,
product_uuid: productUuid,
description,
quantity,
price,
discount_rate: discountRate,
charge_uuid: chargeUuid,
warehouse_uuid: warehouseUuid
}
})
.then(evaluateResponse)
.then(createOrderLineResponse => {
const { convertOrderLine } = require('@/utils/ADempiere/apiConverts/pos.js')
return convertOrderLine(createOrderLineResponse)
}) })
} }
@ -158,35 +275,79 @@ export function updateOrderLine({
price, price,
discountRate discountRate
}) { }) {
return Instance.call(this).updateOrderLine({ return requestRest({
orderLineUuid, url: '/pos/update-order-line',
data: {
is_add_quantity: true,
order_line_uuid: orderLineUuid,
description, description,
quantity, quantity,
price, price,
discountRate discount_rate: discountRate
}
})
.then(evaluateResponse)
.then(createOrderLineResponse => {
const { convertOrderLine } = require('@/utils/ADempiere/apiConverts/pos.js')
return convertOrderLine(createOrderLineResponse)
}) })
} }
// delete Order Line // delete Order Line
export function deleteOrderLine({ export function requestDeleteOrderLine({
orderLineUuid orderLineUuid
}) { }) {
return Instance.call(this).deleteOrderLine({ return requestRest({
orderLineUuid url: '/pos/create-order-line',
data: {
order_line_uuid: orderLineUuid
}
}) })
.then(evaluateResponse)
} }
export function listOrderLines({ export function requestListOrderLines({
orderUuid orderUuid,
pageSize,
pageToken
}) { }) {
return Instance.call(this).listOrderLines({ return requestRest({
orderUuid url: '/pos/list-order-lines',
data: {
order_uuid: orderUuid
},
params: {
page_size: pageSize,
page_token: pageToken
}
})
.then(evaluateResponse)
.then(ordersLineListResponse => {
const { convertOrderLine } = require('@/utils/ADempiere/apiConverts/pos.js')
return {
nextPageToken: ordersLineListResponse.next_page_token,
recordCount: ordersLineListResponse.record_count,
orderLineList: ordersLineListResponse.records.map(productPrice => {
return convertOrderLine(productPrice)
})
}
}) })
} }
export function getKeyLayout({ keyLayoutUuid }) { export function getKeyLayout({ keyLayoutUuid }) {
return Instance.call(this).getKeyLayout({ return requestRest({
keyLayoutUuid url: '/pos/get-key-layout',
data: {
key_layout_uuid: keyLayoutUuid
}
})
.then(evaluateResponse)
.then(keyLayoutResponse => {
const { convertKeyLayout } = require('@/utils/ADempiere/apiConverts/pos.js')
return convertKeyLayout(keyLayoutResponse)
}) })
} }
@ -198,20 +359,35 @@ export function requestListProductPrice({
warehouseUuid, warehouseUuid,
validFrom, validFrom,
// Query // Query
criteria, // criteria,
pageSize, pageSize,
pageToken pageToken
}) { }) {
return Instance.call(this).requestListProductPrice({ return requestRest({
searchValue, url: '/pos/list-product-prices',
priceListUuid, data: {
businessPartnerUuid, price_list_uuid: priceListUuid,
warehouseUuid, search_value: searchValue,
validFrom, valid_from: validFrom,
// Query business_partner_uuid: businessPartnerUuid,
criteria, warehouse_uuid: warehouseUuid
pageSize, },
pageToken params: {
page_size: pageSize,
page_token: pageToken
}
})
.then(evaluateResponse)
.then(productPriceListResponse => {
const { convertProductPrice } = require('@/utils/ADempiere/apiConverts/core.js')
return {
nextPageToken: productPriceListResponse.next_page_token,
recordCount: productPriceListResponse.record_count,
productPricesList: productPriceListResponse.records.map(productPrice => {
return convertProductPrice(productPrice)
})
}
}) })
} }

View File

@ -1,7 +1,11 @@
// Get Instance for connection // Get Instance for connectionimport {
import { POSInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
export function getProductPrice({ // List Point of sales
export function requestGetProductPrice({
searchValue, searchValue,
upc, upc,
value, value,
@ -11,14 +15,23 @@ export function getProductPrice({
warehouseUuid, warehouseUuid,
validFrom validFrom
}) { }) {
return Instance.call(this).getProductPrice({ return requestRest({
searchValue, url: '/pos/get-product-price',
data: {
search_value: searchValue,
upc, upc,
value, value,
name, name,
priceListUuid, price_list_uuid: priceListUuid,
businessPartnerUuid, business_partner_uuid: businessPartnerUuid,
warehouseUuid, warehouse_uuid: warehouseUuid,
validFrom valid_from: validFrom
}
})
.then(evaluateResponse)
.then(productPriceResponse => {
const { convertProductPrice } = require('@/utils/ADempiere/apiConverts/core.js')
return convertProductPrice(productPriceResponse)
}) })
} }

View File

@ -1,85 +1,72 @@
// Get Instance for connection System Core /**
export const SystemCoreInstance = () => { * Instance for connection to API RESTful with axios
const SystemCore = require('@adempiere/grpc-core-client') * @author EdwinBetanc0urt <EdwinBetanc0urt@oulook.com>
const { BUSINESS_DATA_ADDRESS } = require('@/api/ADempiere/constants') * @param {string} url to resource request
const { getLanguage } = require('@/lang/index') * @param {string} method rest, 'get' and 'post' (as default)
const { getToken, getCurrentOrganization, getCurrentWarehouse } = require('@/utils/auth') * @param {object} data body to send post request
* @param {object} params to send get uri
return new SystemCore({ * @param {string} responseType default is 'json'
host: BUSINESS_DATA_ADDRESS, * @returns {function}
sessionUuid: getToken(), */
organizationUuid: getCurrentOrganization(), export function ApiRest({
warehouseUuid: getCurrentWarehouse(), url,
language: getLanguage() || 'en_US' method = 'post',
data = {},
params = {},
responseType = 'json'
}) {
const setInterceptor = (request) => {
request.interceptors.response.use(response => {
return response.data
}, error => {
return Promise.reject(error)
}) })
return request.interceptors
} }
const { API_REST_ADDRESS } = require('@/api/ADempiere/constants.js')
const axios = require('axios')
// Instance for connection Access (or Security) const request = axios.create({
export const AccessInstance = () => { baseURL: API_REST_ADDRESS,
const Access = require('@adempiere/grpc-access-client') // timeout: 10000, // 10s
const { ACCESS_ADDRESS } = require('@/api/ADempiere/constants') headers: {
const { getLanguage } = require('@/lang/index') 'Content-Type': 'application/json;charset=UTF-8'
},
return new Access({ responseType
host: ACCESS_ADDRESS,
version: 'Version Epale',
language: getLanguage() || 'en_US'
}) })
} request.interceptors = setInterceptor(request)
// Instance for connection Business Data
export const BusinessDataInstance = () => {
const BusinessData = require('@adempiere/grpc-data-client')
const { BUSINESS_DATA_ADDRESS } = require('@/api/ADempiere/constants')
const { getLanguage } = require('@/lang/index')
const { getToken, getCurrentOrganization, getCurrentWarehouse } = require('@/utils/auth')
return new BusinessData({
host: BUSINESS_DATA_ADDRESS,
sessionUuid: getToken(),
organizationUuid: getCurrentOrganization(),
warehouseUuid: getCurrentWarehouse(),
language: getLanguage() || 'en_US'
})
}
// Get Instance for connection
export const DictionaryInstance = () => {
const Dictionary = require('@adempiere/grpc-dictionary-client')
const { DICTIONARY_ADDRESS } = require('@/api/ADempiere/constants')
const { getLanguage } = require('@/lang/index')
const { getToken } = require('@/utils/auth') const { getToken } = require('@/utils/auth')
return new Dictionary({
host: DICTIONARY_ADDRESS,
sessionUuid: getToken(),
language: getLanguage() || 'en_US'
})
}
// Instance for connection Enrollment
export const EnrollmentInstance = () => {
const Enrollment = require('@adempiere/grpc-enrollment-client')
const { ENROLLMENT_ADDRESS } = require('@/api/ADempiere/constants')
return new Enrollment(
ENROLLMENT_ADDRESS,
3.9,
'ADempiere-Vue'
)
}
export const POSInstance = () => {
const POS = require('@adempiere/grpc-pos-client')
const { BUSINESS_DATA_ADDRESS } = require('@/api/ADempiere/constants')
const { getLanguage } = require('@/lang/index') const { getLanguage } = require('@/lang/index')
const { getToken, getCurrentOrganization, getCurrentWarehouse } = require('@/utils/auth') const language = getLanguage() || 'en_US'
params = {
token: getToken(),
language,
...params
}
return new POS({ return request({
host: BUSINESS_DATA_ADDRESS, url,
sessionUuid: getToken(), method,
organizationUuid: getCurrentOrganization(), data,
warehouseUuid: getCurrentWarehouse(), params
language: getLanguage() || 'en_US'
}) })
} }
/**
* Evaluate the response if is a success or error
* @author EdwinBetanc0urt <EdwinBetanc0urt@oulook.com>
* @param {object} response
* @returns {mixed}
*/
export const evaluateResponse = (response) => {
if (response.code >= 400) {
const error = {
code: response.code,
message: response.result
}
throw error
}
return response.result
}

View File

@ -1,20 +1,37 @@
// Get Instance for connection // Get Instance for connection
import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
/** /**
* Create entity * Create entity
* @param {string} tableName * @param {string} tableName
* @param {array} attributesList * @param {array} attributesList
*/ */
export function createEntity({ export function requestCreateEntity({
tableName, tableName,
attributes, attributesList
formatReturn = 'array'
}) { }) {
return Instance.call(this).requestCreateEntity({ attributesList = attributesList.map(parameter => {
tableName, return {
attributesList: attributes, key: parameter.columnName,
formatToConvert: formatReturn value: parameter.value
}
})
return requestRest({
url: '/data/create',
data: {
table_name: tableName,
attributes: attributesList
}
})
.then(evaluateResponse)
.then(entityCreateResponse => {
const { convertEntity } = require('@/utils/ADempiere/apiConverts/persistence.js')
return convertEntity(entityCreateResponse)
}) })
} }
@ -25,19 +42,33 @@ export function createEntity({
* @param {string} recordUuid * @param {string} recordUuid
* @param {array} attributesList * @param {array} attributesList
*/ */
export function updateEntity({ export function requestUpdateEntity({
tableName, tableName,
recordId, recordId,
recordUuid, recordUuid,
attributes, attributesList
formatReturn = 'array'
}) { }) {
return Instance.call(this).requestUpdateEntity({ attributesList = attributesList.map(parameter => {
tableName, return {
recordId, key: parameter.columnName,
recordUuid, value: parameter.value
attributesList: attributes, }
formatToConvert: formatReturn })
return requestRest({
url: '/data/update',
data: {
table_name: tableName,
id: recordId,
uuid: recordUuid,
attributes: attributesList
}
})
.then(evaluateResponse)
.then(entityUpdateResponse => {
const { convertEntity } = require('@/utils/ADempiere/apiConverts/persistence.js')
return convertEntity(entityUpdateResponse)
}) })
} }
@ -47,12 +78,19 @@ export function updateEntity({
* @param {number} recordId * @param {number} recordId
* @param {string} recordUuid * @param {string} recordUuid
*/ */
export function deleteEntity({ tableName, recordId, recordUuid }) { export function requestDeleteEntity({
return Instance.call(this).requestDeleteEntity({
tableName, tableName,
recordId, recordId,
recordUuid recordUuid
}) }) {
return requestRest({
url: '/data/delete',
data: {
table_name: tableName,
id: recordId,
uuid: recordUuid
}
}).then(evaluateResponse)
} }
/** /**
@ -64,21 +102,46 @@ export function deleteEntity({ tableName, recordId, recordUuid }) {
export function rollbackEntity({ export function rollbackEntity({
tableName, tableName,
recordId, recordId,
recordUuid,
eventType eventType
}) { }) {
return Instance.call(this).requestRollbackEntity({ return requestRest({
tableName, url: '/data/rollback-entity',
recordId, data: {
eventTypeExecuted: eventType table_name: tableName,
id: recordId,
uuid: recordUuid,
event_type: eventType
}
})
.then(evaluateResponse)
.then(entityResponse => {
const { convertEntity } = require('@/utils/ADempiere/apiConverts/persistence.js')
return convertEntity(entityResponse)
}) })
} }
// Get entity from table name and record id or record uuid // Get entity from table name and record id or record uuid
export function getEntity({ tableName, recordId, recordUuid }) { export function requestGetEntity({
return Instance.call(this).requestGetEntity({
tableName, tableName,
recordId, recordId,
recordUuid recordUuid
}) {
return requestRest({
url: '/data/entity',
method: 'get',
params: {
table_name: tableName,
uuid: recordUuid,
id: recordId
}
})
.then(evaluateResponse)
.then(entityResponse => {
const { convertEntity } = require('@/utils/ADempiere/apiConverts/persistence.js')
return convertEntity(entityResponse)
}) })
} }
@ -88,26 +151,56 @@ export function getEntity({ tableName, recordId, recordUuid }) {
* @param {string} query * @param {string} query
* @param {string} whereClause * @param {string} whereClause
* @param {array} conditionsList * @param {array} conditionsList
* @param {array} columnsList // TODO: Add support on adempiere-vue
* @param {string} orderByClause * @param {string} orderByClause
* @param {string} pageToken * @param {string} pageToken
*/ */
export function getEntitiesList({ export function requestListEntities({
tableName, tableName,
query, query,
whereClause, whereClause,
conditionsList = [], conditionsList = [],
columnsList = [],
orderByClause, orderByClause,
limit,
pageToken, pageToken,
pageSize pageSize
}) { }) {
return Instance.call(this).requestListEntities({ const filters = conditionsList.map(condition => {
tableName, const { value, operator, columnName, valueTo, values } = condition
return {
column_name: columnName,
value,
operator,
value_to: valueTo,
values
}
})
return requestRest({
url: '/data/list',
data: {
table_name: tableName,
// DSL Query
filters,
columns: columnsList,
// Custom Query
query, query,
whereClause, where_clause: whereClause,
conditionsList, order_by_clause: orderByClause,
orderByClause, limit
},
params: {
// Page Data
pageToken, pageToken,
pageSize pageSize
}
})
.then(evaluateResponse)
.then(entitiesListResponse => {
const { convertEntityList } = require('@/utils/ADempiere/apiConverts/persistence.js')
return convertEntityList(entitiesListResponse)
}) })
} }
@ -118,25 +211,54 @@ export function getEntitiesList({
* @param {string} recordUuid * @param {string} recordUuid
* @param {number} recordId * @param {number} recordId
*/ */
export function requestTranslations({ tableName, language, recordUuid, recordId, pageToken, pageSize }) { export function requestTranslations({
return Instance.call(this).requestListTranslations({
tableName, tableName,
language,
recordUuid, recordUuid,
recordId, recordId,
language,
pageToken, pageToken,
pageSize pageSize
}) {
return requestRest({
url: '/ui/list-translations',
data: {
table_name: tableName,
id: recordId,
uuid: recordUuid
},
params: {
language,
// Page Data
pageToken,
pageSize
}
})
.then(evaluateResponse)
.then(languageListResponse => {
const { convertTranslation } = require('@/utils/ADempiere/apiConverts/persistence.js')
return {
nextPageToken: languageListResponse.next_page_token,
recordCount: languageListResponse.record_count,
translationsList: languageListResponse.records.map(record => {
return convertTranslation(record)
})
}
}) })
} }
// Download a resource from file name // Download a resource from file name
export function getResource({ resourceUuid }, callBack = { export function requestResource({ resourceUuid }, callBack = {
onData: () => {}, onData: () => {},
onStatus: () => {}, onStatus: () => {},
onEnd: () => {} onEnd: () => {}
}) { }) {
const stream = Instance.call(this).getResource({ const stream = requestRest({
resourceUuid url: '/resource',
method: 'get',
params: {
resource_uuid: resourceUuid
}
}) })
stream.on('data', (response) => callBack.onData(response)) stream.on('data', (response) => callBack.onData(response))
@ -145,3 +267,34 @@ export function getResource({ resourceUuid }, callBack = {
return stream return stream
} }
/**
* Get image with uri request
* @author EdwinBetanc0urt <EdwinBetanc0urt@oulook.com>
* @param {string} file
* @param {number} width
* @param {number} height
* @param {string} operation fit, resize
* @returns {promise} with array buffer in response
*/
export function requestImage({
file,
width = 300,
height = 300,
operation = 'fit'
}) {
const { getImagePath } = require('@/utils/ADempiere/resource.js')
const { urn } = getImagePath({
file,
width,
height,
operation
})
return requestRest({
url: urn,
method: 'get',
responseType: 'arraybuffer'
})
}

View File

@ -1,29 +1,66 @@
// Get Instance for connection // Get Instance for connection
import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
import { convertPrivateAccess } from '@/utils/ADempiere/apiConverts/privateAccess.js'
// Get private access for a record // Get private access for a record
export function getPrivateAccessFromServer({ tableName, recordId, userUuid }) { export function requestGetPrivateAccess({
return Instance.call(this).requestGetPrivateAccess({
tableName, tableName,
recordId, recordId,
userUuid recordUuid
}) {
return requestRest({
url: '/ui/get-private-access',
data: {
table_name: tableName,
id: recordId,
uuid: recordUuid
}
})
.then(evaluateResponse)
.then(responsePrivateAccess => {
return convertPrivateAccess(responsePrivateAccess)
}) })
} }
// Lock a record for a user // Lock a record for a user
export function lockPrivateAccessFromServer({ tableName, recordId, userUuid }) { export function requestLockPrivateAccess({
return Instance.call(this).requestLockPrivateAccess({
tableName, tableName,
recordId, recordId,
userUuid recordUuid
}) {
return requestRest({
url: '/ui/lock-private-access',
data: {
table_name: tableName,
id: recordId,
uuid: recordUuid
}
})
.then(evaluateResponse)
.then(responsePrivateAccess => {
return convertPrivateAccess(responsePrivateAccess)
}) })
} }
// Unlock a record from a user // Unlock a record from a user
export function unlockPrivateAccessFromServer({ tableName, recordId, userUuid }) { export function requestUnlockPrivateAccess({
return Instance.call(this).requestUnlockPrivateAccess({
tableName, tableName,
recordId, recordId,
userUuid recordUuid
}) {
return requestRest({
url: '/ui/unlock-private-access',
data: {
table_name: tableName,
id: recordId,
uuid: recordUuid
}
})
.then(evaluateResponse)
.then(responsePrivateAccess => {
return convertPrivateAccess(responsePrivateAccess)
}) })
} }

View File

@ -1,13 +1,17 @@
// Get Instance for connection // Get Instance for connection
import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
/** /**
* Request a process * Request a process
* This function allows follow structure: * This function allows follow structure:
* @param {string} uuid, uuid from process to run * @param {string} uuid, uuid from process to run
* @param {number} reportType * @param {string} reportType, format to output report (pdf, html, csv, ...)
* @param {number} tableName, table name of tab, used only window * @param {string} tableName, table name of tab, used only window
* @param {number} recordId, record identifier, used only window * @param {number} recordId, record identifier, used only window
* @param {string} recordUuid, record universal unique identifier, used only window
* @param {array} parametersList, parameters from process [{ columnName, value }] * @param {array} parametersList, parameters from process [{ columnName, value }]
* @param {array} selectionsList, selection records, used only browser * @param {array} selectionsList, selection records, used only browser
[{ [{
@ -15,22 +19,89 @@ import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js'
selectionValues: [{ columnName, value }] selectionValues: [{ columnName, value }]
}] }]
* @param {string} printFormatUuid * @param {string} printFormatUuid
* @param {boolean} isSummary
* @param {number} tableSelectedId, used only browser // TODO: Add support on adempiere-vue
* @param {string} reportViewUuid
*/ */
export function runProcess({ uuid, reportType, tableName, recordId, parametersList = [], selectionsList = [], printFormatUuid }) { export function requestRunProcess({
// Run Process
return Instance.call(this).requestRunProcess({
uuid, uuid,
reportType, reportType,
tableName, tableName,
recordId, recordId,
parametersList, recordUuid,
selectionsList, parametersList = [],
printFormatUuid selectionsList = [],
isSummary,
tableSelectedId,
printFormatUuid,
reportViewUuid
}) {
parametersList = parametersList.map(parameter => {
return {
key: parameter.columnName,
value: parameter.value
}
})
return requestRest({
url: '/data/process',
data: {
process_uuid: uuid,
table_name: tableName,
id: recordId,
uuid: recordUuid,
is_summary: isSummary,
report_type: reportType,
table_selected_id: tableSelectedId,
report_view_uuid: reportViewUuid,
parameters: parametersList,
selections: selectionsList,
print_format_uuid: printFormatUuid
}
})
.then(evaluateResponse)
.then(processRunResponse => {
const { convertProcessLog } = require('@/utils/ADempiere/apiConverts/process.js')
return convertProcessLog(processRunResponse)
}) })
} }
// Request a Process Activity list // Request a Process Activity list
export function requestListProcessesLogs({ pageToken, pageSize }) { export function requestListProcessesLogs({
tableName,
instanceUuid,
userUuid,
recordId,
recordUuid,
pageToken,
pageSize
}) {
// Get Process Activity // Get Process Activity
return Instance.call(this).requestListProcessesLogs({ pageToken, pageSize }) return requestRest({
url: '/logs/list-process-logs',
data: {
instance_uuid: instanceUuid,
user_uuid: userUuid,
table_name: tableName,
id: recordId,
uuid: recordUuid
},
params: {
page_size: pageSize,
page_token: pageToken
}
})
.then(evaluateResponse)
.then(processLogResponse => {
const { convertProcessLog } = require('@/utils/ADempiere/apiConverts/process.js')
return {
recordCount: processLogResponse.record_count,
processLogsList: processLogResponse.records.map(itemProcess => {
return convertProcessLog(itemProcess)
}),
nextPageToken: processLogResponse.next_page_token
}
})
} }

View File

@ -1,57 +1,139 @@
// Get Instance for connection // Get Instance for connection
import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
/** /**
* Request Pending Documents List * Request Pending Documents List
* @param {string} tableName * @param {string} tableName
* @param {string} processUuid * @param {string} processUuid
*/ */
export function requestReportViews({ tableName, processUuid, pageToken, pageSize }) { export function requestListReportsViews({
return Instance.call(this).requestListReportViews({
tableName, tableName,
processUuid, processUuid,
pageToken, pageToken,
pageSize pageSize
}) {
return requestRest({
url: '/ui/list-report-views',
data: {
table_name: tableName,
process_uuid: processUuid
},
params: {
page_token: pageToken,
page_size: pageSize
}
})
.then(evaluateResponse)
.then(reportViewResponse => {
const { convertReportView } = require('@/utils/ADempiere/apiConverts/report.js')
return {
nextPageToken: reportViewResponse.next_page_token,
recordCount: reportViewResponse.record_count,
reportViewsList: reportViewResponse.records.map(drill => {
return convertReportView(drill)
})
}
}) })
} }
// Get print formats from table name, report view uuid or process uuid // Get print formats from table name, report view uuid or process uuid
export function requestPrintFormats({ tableName, reportViewUuid, processUuid, pageToken, pageSize }) { export function requestListPrintFormats({
return Instance.call(this).requestListPrintFormats({
tableName, tableName,
reportViewUuid, reportViewUuid,
processUuid, processUuid,
pageToken, pageToken,
pageSize pageSize
}) {
return requestRest({
url: '/ui/list-print-formats',
data: {
table_name: tableName,
report_view_uuid: reportViewUuid,
process_uuid: processUuid
},
params: {
page_token: pageToken,
page_size: pageSize
}
})
.then(evaluateResponse)
.then(responseListPrintFormats => {
const { convertListPrintFormats } = require('@/utils/ADempiere/apiConverts/report.js')
return convertListPrintFormats(responseListPrintFormats)
}) })
} }
// Get drill tables for a report // Get drill tables for a report
export function requestDrillTables({ tableName, pageToken, pageSize }) { export function requestListDrillTables({
return Instance.call(this).requestListDrillTables({
tableName, tableName,
pageToken, pageToken,
pageSize pageSize
}) {
requestRest({
url: '/ui/list-drill-tables',
data: {
table_name: tableName
},
params: {
page_token: pageToken,
page_size: pageSize
}
})
.then(evaluateResponse)
.then(drillTablesResponse => {
const { convertDrillTables } = require('@/utils/ADempiere/apiConverts/report.js')
return {
drillTablesList: drillTablesResponse.records.map(drill => {
return convertDrillTables(drill)
}),
nextPageToken: drillTablesResponse.next_page_token,
recordCount: drillTablesResponse.record_count
}
}) })
} }
// Get report output from parameters // Get report output from parameters
export function getReportOutput({ export function requestGetReportOutput({
parametersList,
tableName, tableName,
printFormatUuid, printFormatUuid,
reportViewUuid, reportViewUuid,
isSummary, isSummary,
reportName, reportName,
reportType reportType,
parametersList,
// query criteria
query,
whereClause,
orderByClause
}) { }) {
return Instance.call(this).requestGetReportOutput({ return requestRest({
parametersList, url: '/ui/get-report-output',
tableName, data: {
printFormatUuid, table_name: tableName,
reportViewUuid, // reference
isSummary, print_format_uuid: printFormatUuid,
reportName, report_view_uuid: reportViewUuid,
reportType is_summary: isSummary,
report_name: reportName,
report_type: reportType,
// DSL Query
filters: parametersList,
// Custom Query
query,
where_clause: whereClause,
order_by_clause: orderByClause
}
})
.then(evaluateResponse)
.then(reportOutpuResponse => {
const { convertReportOutput } = require('@/utils/ADempiere/apiConverts/report.js')
return convertReportOutput(reportOutpuResponse)
}) })
} }

View File

@ -1,5 +1,8 @@
// Get Instance for connection // Get Instance for connection
import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
/** /**
* Run callout request * Run callout request
@ -14,8 +17,7 @@ import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js'
* @param {array} attributesList * @param {array} attributesList
* @returns {Map} Entity * @returns {Map} Entity
*/ */
export function runCallOutRequest({ windowUuid, windowNo, tabUuid, tableName, columnName, value, oldValue, valueType, callout, attributesList = [] }) { export function runCallOutRequest({
return Instance.call(this).requestRunCallout({
windowUuid, windowUuid,
windowNo, windowNo,
tabUuid, tabUuid,
@ -23,8 +25,22 @@ export function runCallOutRequest({ windowUuid, windowNo, tabUuid, tableName, co
columnName, columnName,
value, value,
oldValue, oldValue,
valueType,
callout, callout,
attributesList attributesList = []
}) }) {
return requestRest({
url: '/ui/run-callout',
data: {
table_name: tableName,
window_uuid: windowUuid,
tab_uuid: tabUuid,
callout,
column_name: columnName,
old_value: oldValue,
value,
window_no: windowNo,
attributes: attributesList
}
})
.then(evaluateResponse)
} }

View File

@ -1,45 +1,68 @@
// Get Instance for connection // Get Instance for connection
import { BusinessDataInstance as Instance, SystemCoreInstance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
/** evaluateResponse
* Checks if value is empty. Deep-checks arrays and objects } from '@/api/ADempiere/instances.js'
* Note: isEmpty([]) == true, isEmpty({}) == true, isEmpty([{0:false},"",0]) == true, isEmpty({0:1}) == false
* @param {boolean|array|object|number|string|date|map|set|function} value
* @returns {boolean}
*/
export function isEmptyValue(value) {
const { isEmptyValue } = require('@adempiere/grpc-core-client/src/convertValues.js')
return isEmptyValue(value)
}
// Get Organization list from role // Get Organization list from role
export function getOrganizationsList({ export function requestOrganizationsList({
roleUuid, roleUuid,
roleId, roleId,
pageToken, pageToken,
pageSize pageSize
}) { }) {
return Instance.call(this).requestListOrganizations({ return requestRest({
roleUuid, url: '/core/list-organizations',
roleId, data: {
role_id: roleId,
role_uuid: roleUuid
},
params: {
// Page Data
pageToken, pageToken,
pageSize pageSize
}
})
.then(evaluateResponse)
.then(organizationsListResponse => {
const { convertOrganization } = require('@/utils/ADempiere/apiConverts/core.js')
return {
nextPageToken: organizationsListResponse.next_page_token,
recordCount: organizationsListResponse.record_count,
organizationsList: organizationsListResponse.records.map(organization => {
return convertOrganization(organization)
})
}
}) })
} }
// Get Warehouses of Organization // Get Warehouses of Organization
export function getWarehousesList({ export function requestWarehousesList({
organizationUuid, organizationUuid,
organizationId, organizationId,
pageToken, pageToken,
pageSize pageSize
}) { }) {
return Instance.call(this).requestListWarehouses({ return requestRest({
organizationUuid, url: '/core/list-warehouses',
organizationId, data: {
organization_id: organizationId,
organization_uuid: organizationUuid
},
params: {
// Page Data
pageToken, pageToken,
pageSize pageSize
}
})
.then(evaluateResponse)
.then(warehousesListResponse => {
return {
nextPageToken: warehousesListResponse.next_page_token,
recordCount: warehousesListResponse.record_count,
warehousesList: warehousesListResponse.records
}
}) })
} }
@ -48,16 +71,51 @@ export function getWarehousesList({
* @param {string} uuid * @param {string} uuid
* @param {number} id * @param {number} id
*/ */
export function getCountryDefinition({ uuid, id }) { export function requestGetCountryDefinition({
return SystemCoreInstance.call(this).requestGetCountry({ id,
uuid, uuid
id }) {
return requestRest({
url: '/core/country',
method: 'get',
params: {
id,
uuid
}
})
.then(evaluateResponse)
.then(countryResponse => {
const { convertCountry } = require('@/utils/ADempiere/apiConverts/core.js')
return convertCountry(countryResponse)
}) })
} }
// Get languages from api // Get languages from api
export function listLanguages({ pageToken, pageSize }) { export function requestLanguagesList({
return Instance.call(this).requestListLanguages({ pageToken, pageSize }) pageToken,
pageSize
}) {
return requestRest({
url: '/core/list-languages',
params: {
// Page Data
pageToken,
pageSize
}
})
.then(evaluateResponse)
.then(languagesListResponse => {
const { convertLanguage } = require('@/utils/ADempiere/apiConverts/core.js')
return {
nextPageToken: languagesListResponse.next_page_token,
recordCount: languagesListResponse.record_count,
languagesList: languagesListResponse.records.map(language => {
return convertLanguage(language)
})
}
})
} }
export function requestCreateBusinessPartner({ export function requestCreateBusinessPartner({
@ -85,38 +143,57 @@ export function requestCreateBusinessPartner({
countryUuid, countryUuid,
posUuid posUuid
}) { }) {
return SystemCoreInstance.call(this).requestCreateBusinessPartner({ return requestRest({
url: '/core/create-business-partner',
data: {
value, value,
taxId, tax_id: taxId,
duns, duns,
naics, naics,
name, name,
lastName, last_name: lastName,
description, description,
contactName, contact_name: contactName,
eMail, e_mail: eMail,
phone, phone,
businessPartnerGroupUuid, business_partner_group_uid: businessPartnerGroupUuid,
// Location // Location
address1, address1,
address2, address2,
address3, address3,
address4, address4,
cityUuid, city_uuid: cityUuid,
cityName, city_name: cityName,
postalCode, postal_code: postalCode,
regionUuid, region_uuid: regionUuid,
regionName, region_name: regionName,
countryUuid, country_uuid: countryUuid,
posUuid pos_uuid: posUuid
}
})
.then(evaluateResponse)
.then(businessPartnerResponse => {
const { convertBusinessPartner } = require('@/utils/ADempiere/apiConverts/core.js')
return convertBusinessPartner(businessPartnerResponse)
}) })
} }
export function requestGetBusinessPartner({ export function requestGetBusinessPartner({
searchValue searchValue
}) { }) {
return SystemCoreInstance.call(this).requestGetBusinessPartner({ return requestRest({
searchValue url: '/core/get-business-partner',
method: 'get',
params: {
search_value: searchValue
}
})
.then(evaluateResponse)
.then(businessPartnerResponse => {
const { convertBusinessPartner } = require('@/utils/ADempiere/apiConverts/core.js')
return convertBusinessPartner(businessPartnerResponse)
}) })
} }
@ -129,21 +206,68 @@ export function requestListBusinessPartner({
postalCode, postalCode,
phone, phone,
// Query // Query
criteria, // criteria,
pageSize, pageSize,
pageToken pageToken
}) { }) {
return SystemCoreInstance.call(this).requestListBusinessPartner({ return requestRest({
searchValue, url: '/core/list-business-partner',
data: {
search_value: searchValue,
value, value,
name, name,
contactName, contact_name: contactName,
eMail, e_mail: eMail,
postalCode,
phone, phone,
// Query // Location
criteria, postal_code: postalCode
pageSize, },
pageToken params: {
page_size: pageSize,
page_token: pageToken
}
})
.then(evaluateResponse)
.then(businessPartnerResponse => {
const { convertBusinessPartner } = require('@/utils/ADempiere/apiConverts/core.js')
return {
nextPageToken: businessPartnerResponse.next_page_token,
recordCount: businessPartnerResponse.record_count,
businessPartnersList: businessPartnerResponse.records.map(businessPartner => {
return convertBusinessPartner(businessPartner)
})
}
})
}
/**
* TODO: Add uuid support
* @param {string} conversionTypeUuid
* @param {string} currencyFromUuid
* @param {string} currencyToUuid
* @param {date} conversionDate
* @returns {promise}
*/
export function requestGetConversionRate({
conversionTypeUuid,
currencyFromUuid,
currencyToUuid,
conversionDate
}) {
return requestRest({
url: '/core/get-conversion-rate',
data: {
conversion_type_uuid: conversionTypeUuid,
currency_from_uuid: currencyFromUuid,
currency_to_uuid: currencyToUuid,
conversion_date: conversionDate
}
})
.then(evaluateResponse)
.then(conversionRateResponse => {
const { convertConversionRate } = require('@/utils/ADempiere/apiConverts/core.js')
return convertConversionRate(conversionRateResponse)
}) })
} }

View File

@ -0,0 +1,48 @@
// Get Instance for connection
import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
/**
* Get Attachment
* @param {number} recordId
* @param {string} recordUuid // TODO: Add suppport to record uuid on backend
*/
export function requestResourceReference({
recordId,
recordUuid
}) {
return requestRest({
url: '/ui/resource-reference',
method: 'get',
params: {
image_id: recordId,
image_uuid: recordUuid
}
})
.then(evaluateResponse)
}
/**
* Get Attachment
* @param {string} tableName
* @param {number} recordId
* @param {string} recordUuid
*/
export function requestAttachment({
tableName,
recordId,
recordUuid
}) {
return requestRest({
url: '/ui/attachment',
method: 'get',
params: {
table_name: tableName,
id: recordId,
uuid: recordUuid
}
})
.then(evaluateResponse)
}

View File

@ -1,23 +1,40 @@
// Get Instance for connection // Get Instance for connection
import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
import { isEmptyValue } from '@/utils/ADempiere/valueUtils.js'
/** /**
* Request a Lookup data from Reference * Request a Lookup data from Reference
* The main attributes that function hope are: * The main attributes that function hope are:
* @param {string} columnName
* @param {string} tableName * @param {string} tableName
* @param {string} directQuery * @param {string} directQuery
* @param {string|number} value * @param {string|number} value
*/ */
export function requestLookup({ export function requestLookup({
columnName,
tableName, tableName,
directQuery, directQuery,
value value
}) { }) {
return Instance.call(this).requestLookupFromReference({ let filters = []
tableName, if (!isEmptyValue(value)) {
directQuery, filters = [{
column_name: columnName,
value value
}]
}
return requestRest({
url: '/ui/get-lookup-item',
data: {
table_name: tableName,
query: directQuery,
filters
}
}) })
.then(evaluateResponse)
} }
/** /**
@ -25,23 +42,49 @@ export function requestLookup({
* The main attributes that function hope are: * The main attributes that function hope are:
* @param {string} tableName * @param {string} tableName
* @param {string} query * @param {string} query
* @param {Array<String>|<Number>} valuesList * @param {string} whereClause
* @param {array} valuesList // TODO: Add support
* @param {string} pageToken * @param {string} pageToken
* @param {number} pageSize * @param {number} pageSize
*/ */
export function requestLookupList({ export function requestLookupList({
tableName, tableName,
query, query,
whereClause,
columnName,
valuesList = [], valuesList = [],
pageToken, pageToken,
pageSize pageSize
}) { }) {
return Instance.call(this).requestListLookupFromReference({ let filters = []
tableName, if (!isEmptyValue(valuesList)) {
filters = [{
column_name: columnName,
values: valuesList
}]
}
return requestRest({
url: '/ui/list-lookup-items',
data: {
table_name: tableName,
query, query,
valuesList, where_clause: whereClause,
filters
},
params: {
// Page Data
pageToken, pageToken,
pageSize pageSize
}
})
.then(evaluateResponse)
.then(lookupListResponse => {
return {
nextPageToken: lookupListResponse.next_page_token,
recordCount: lookupListResponse.record_count,
recordsList: lookupListResponse.records
}
}) })
} }
@ -52,23 +95,71 @@ export function requestLookupList({
* @param {string} recordUuid * @param {string} recordUuid
* @param {number} recordId * @param {number} recordId
*/ */
export function getReferencesList({ windowUuid, tableName, recordId, recordUuid, pageToken, pageSize }) { export function requestReferencesList({
return Instance.call(this).requestListReferences({
windowUuid, windowUuid,
tableName, tableName,
recordId, recordId,
recordUuid, recordUuid,
pageToken, pageToken,
pageSize pageSize
}) {
return requestRest({
url: '/ui/list-references',
data: {
id: recordId,
uuid: recordUuid,
window_uuid: windowUuid,
table_name: tableName
},
params: {
// Page Data
pageToken,
pageSize
}
})
.then(evaluateResponse)
.then(referencesListResposnse => {
const { convertReferencesList } = require('@/utils/ADempiere/apiConverts/values.js')
return convertReferencesList(referencesListResposnse)
}) })
} }
// Get default value for a field // Get default value for a field
export function getDefaultValueFromServer(query) { export function requestDefaultValue(query) {
return Instance.call(this).requestGetDefaultValue(query) return requestRest({
url: '/ui/get-default-value',
data: {
query
}
})
.then(evaluateResponse)
} }
// Get context information for a window, tab or field /**
export function getContextInfoValueFromServer({ uuid, query }) { * Get context information for a window, tab or field
return Instance.call(this).requestGetContextInfoValue({ uuid, query }) * @param {string} query
* @param {string} uuid
* @param {number} id
*/
export function requestGetContextInfoValue({
uuid,
id,
query
}) {
return requestRest({
url: '/ui/get-context-info-value',
data: {
query,
uuid,
id
}
})
.then(evaluateResponse)
.then(contextInfoValueResponse => {
return {
messageText: contextInfoValueResponse.message_text,
messageTip: contextInfoValueResponse.message_tip
}
})
} }

View File

@ -1,18 +1,41 @@
// Get Instance for connection // Get Instance for connection
import { BusinessDataInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
// Get list of log for a records // Get list of log for a records
export function requestListRecordsLogs({ export function requestListEntityLogs({
tableName, tableName,
recordId, recordId,
recordUuid,
pageToken, pageToken,
pageSize pageSize
}) { }) {
return Instance.call(this).requestListRecordsLogs({ return requestRest({
tableName, url: '/logs/list-entity-logs',
recordId, data: {
table_name: tableName,
id: recordId,
uuid: recordUuid
},
params: {
// Page Data
pageToken, pageToken,
pageSize pageSize
}
})
.then(evaluateResponse)
.then(entityLogsListResponse => {
const { convertEntityLog } = require('@/utils/ADempiere/apiConverts/window.js')
return {
nextPageToken: entityLogsListResponse.next_page_token,
recordCount: entityLogsListResponse.record_count,
entityLogsList: entityLogsListResponse.records.map(entityLog => {
return convertEntityLog(entityLog)
})
}
}) })
} }
@ -20,14 +43,34 @@ export function requestListRecordsLogs({
export function requestListWorkflowsLogs({ export function requestListWorkflowsLogs({
tableName, tableName,
recordId, recordId,
recordUuid,
pageToken, pageToken,
pageSize pageSize
}) { }) {
return Instance.call(this).requestListWorkflowsLogs({ return requestRest({
tableName, url: '/logs/list-workflow-logs',
recordId, data: {
table_name: tableName,
id: recordId,
uuid: recordUuid
},
params: {
// Page Data
pageToken, pageToken,
pageSize pageSize
}
})
.then(evaluateResponse)
.then(workflowLogsListResponse => {
const { convertWorkflowProcess } = require('@/utils/ADempiere/apiConverts/window.js')
return {
nextPageToken: workflowLogsListResponse.next_page_token,
recordCount: workflowLogsListResponse.record_count,
workflowLogsList: workflowLogsListResponse.records.map(workflowLog => {
return convertWorkflowProcess(workflowLog)
})
}
}) })
} }
@ -37,10 +80,28 @@ export function requestListWorkflows({
pageToken, pageToken,
pageSize pageSize
}) { }) {
return Instance.call(this).requestListWorkflows({ return requestRest({
tableName, url: '/workflow/list-workflow',
data: {
table_name: tableName
},
params: {
// Page Data
pageToken, pageToken,
pageSize pageSize
}
})
.then(evaluateResponse)
.then(workflowListResponse => {
const { convertWorkflowDefinition } = require('@/utils/ADempiere/apiConverts/window.js')
return {
nextPageToken: workflowListResponse.next_page_token,
recordCount: workflowListResponse.record_count,
workflowsList: workflowListResponse.records.map(workflowDefinition => {
return convertWorkflowDefinition(workflowDefinition)
})
}
}) })
} }
@ -50,12 +111,37 @@ export function requestListWorkflows({
* @param {string} pageToken * @param {string} pageToken
* @param {string} pageSize * @param {string} pageSize
*/ */
export function requestListRecordChats({ tableName, recordId, pageToken, pageSize }) { export function requestListEntityChats({
return Instance.call(this).requestListRecordChats({
tableName, tableName,
recordId, recordId,
recordUuid,
pageToken, pageToken,
pageSize pageSize
}) {
return requestRest({
url: '/logs/list-entity-chats',
data: {
table_name: tableName,
id: recordId,
uuid: recordUuid
},
params: {
// Page Data
pageToken,
pageSize
}
})
.then(evaluateResponse)
.then(entityChatListResponse => {
const { convertEntityChat } = require('@/utils/ADempiere/apiConverts/window.js')
return {
nextPageToken: entityChatListResponse.next_page_token,
recordCount: entityChatListResponse.record_count,
entityChatsList: entityChatListResponse.records.map(entityChat => {
return convertEntityChat(entityChat)
})
}
}) })
} }
@ -64,24 +150,64 @@ export function requestListRecordChats({ tableName, recordId, pageToken, pageSiz
* @param {string} pageToken * @param {string} pageToken
* @param {string} pageSize * @param {string} pageSize
*/ */
export function requestListChatEntries({ uuid, pageToken, pageSize }) { export function requestListChatsEntries({
return Instance.call(this).requestListChatEntries({ id,
uuid, uuid,
pageToken, pageToken,
pageSize pageSize
}) {
return requestRest({
url: '/logs/list-chat-entries',
data: {
id,
uuid
},
params: {
// Page Data
pageToken,
pageSize
}
})
.then(evaluateResponse)
.then(chatEntriesListResponse => {
const { convertChatEntry } = require('@/utils/ADempiere/apiConverts/window.js')
return {
nextPageToken: chatEntriesListResponse.next_page_token,
recordCount: chatEntriesListResponse.record_count,
chatEntriesList: chatEntriesListResponse.records.map(chatEntry => {
return convertChatEntry(chatEntry)
})
}
}) })
} }
/** /**
* @param {string} tableName * @param {string} tableName
* @param {string} recordId * @param {string} recordId
* @param {string} recordUuid
* @param {string} comment * @param {string} comment
*/ */
export function requestCreateChatEntry({ tableName, recordId, comment }) { export function requestCreateChatEntry({
return Instance.call(this).requestCreateChatEntry({
tableName, tableName,
recordId, recordId,
recordUuid,
comment comment
}) {
return requestRest({
url: '/ui/create-chat-entry',
data: {
table_name: tableName,
id: recordId,
uuid: recordUuid,
comment: comment
}
})
.then(evaluateResponse)
.then(chatEntryResponse => {
const { convertChatEntry } = require('@/utils/ADempiere/apiConverts/window.js')
return convertChatEntry(chatEntryResponse)
}) })
} }
@ -95,8 +221,7 @@ export function requestCreateChatEntry({ tableName, recordId, comment }) {
* @param {number} pageSize * @param {number} pageSize
* @param {string} pageToken * @param {string} pageToken
*/ */
export function requestListDocumentStatuses({ tableName, recordId, recordUuid, documentStatus, documentAction, pageSize, pageToken }) { export function requestListDocumentStatuses({
return Instance.call(this).requestListDocumentStatuses({
tableName, tableName,
recordId, recordId,
recordUuid, recordUuid,
@ -104,12 +229,34 @@ export function requestListDocumentStatuses({ tableName, recordId, recordUuid, d
documentAction, documentAction,
pageSize, pageSize,
pageToken pageToken
}) {
return requestRest({
url: '/workflow/list-document-actions',
data: {
id: recordId,
uuid: recordUuid,
table_name: tableName,
document_action: documentAction,
document_status: documentStatus
},
params: {
// Page Data
pageToken,
pageSize
}
})
.then(evaluateResponse)
.then(listDocumentsActionsResponse => {
return {
nextPageToken: listDocumentsActionsResponse.next_page_token,
recordCount: listDocumentsActionsResponse.record_count,
documentStatusesList: listDocumentsActionsResponse.records
}
}) })
} }
// Request a document action list from current status of document // Request a document action list from current status of document
export function requestListDocumentActions({ tableName, recordId, recordUuid, documentStatus, documentAction, pageSize, pageToken }) { export function requestListDocumentActions({
return Instance.call(this).requestListDocumentActions({
tableName, tableName,
recordId, recordId,
recordUuid, recordUuid,
@ -117,5 +264,31 @@ export function requestListDocumentActions({ tableName, recordId, recordUuid, do
documentAction, documentAction,
pageSize, pageSize,
pageToken pageToken
}) {
return requestRest({
url: '/workflow/list-document-actions',
data: {
id: recordId,
uuid: recordUuid,
table_name: tableName,
document_action: documentAction,
document_status: documentStatus
},
params: {
// Page Data
pageToken,
pageSize
}
})
.then(evaluateResponse)
.then(listDocumentsActionsResponse => {
return {
nextPageToken: listDocumentsActionsResponse.next_page_token,
recordCount: listDocumentsActionsResponse.record_count,
defaultDocumentAction: {
...listDocumentsActionsResponse.default_document_action
},
documentActionsList: listDocumentsActionsResponse.records
}
}) })
} }

View File

@ -1,4 +1,8 @@
import request from '@/utils/request' import request from '@/utils/request'
import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
export function getRoutes() { export function getRoutes() {
return request({ return request({
@ -14,6 +18,25 @@ export function getRoles() {
}) })
} }
export function requestRolesList(token) {
return requestRest({
url: 'user/roles',
method: 'get',
params: {
token
}
})
.then(evaluateResponse)
.then(responseRoles => {
const { convertRole } = require('@/utils/ADempiere/apiConverts/user.js')
const rolesList = responseRoles.map(itemRol => {
return convertRole(itemRol)
})
return rolesList
})
}
export function addRole(data) { export function addRole(data) {
return request({ return request({
url: '/vue-element-admin/role', url: '/vue-element-admin/role',
@ -36,3 +59,31 @@ export function deleteRole(id) {
method: 'delete' method: 'delete'
}) })
} }
/**
* Change role of access
* @param {string} roleUuid
* @param {string} organizationUuid
* @param {string} warehouseUuid
*/
export function requestChangeRole({
roleUuid,
organizationUuid,
warehouseUuid
}) {
return requestRest({
url: 'user/change-role',
method: 'post',
data: {
role: roleUuid,
organization: organizationUuid,
warehouse: warehouseUuid
}
})
.then(evaluateResponse)
.then(responseChangeRole => {
const { convertSession } = require('@/utils/ADempiere/apiConverts/user.js')
return convertSession(responseChangeRole)
})
}

View File

@ -1,54 +1,89 @@
// Instance for connection // Instance for connection
import { AccessInstance as Instance } from '@/api/ADempiere/instances.js' import {
ApiRest as requestRest,
evaluateResponse
} from '@/api/ADempiere/instances.js'
// Make login by UserName and password, this function can return user data for show /**
* Make login by UserName and password, this function can return user data for show
* @param {string} userName
* @param {string} password
*/
export function login({ export function login({
userName, userName,
password: userPass, password
role
}) { }) {
if (role && role.trim() !== '') { return requestRest({
return Instance.call(this).requestLogin({ url: '/user/login',
userName, method: 'post',
userPass, data: {
role username: userName,
}) password
} }
return Instance.call(this).requestLoginDefault({
userName,
userPass
}) })
} }
// Get User Info from session Uuid or token /**
* Get User Info
* @param {string} token or session UUID
*/
export function requestUserInfoFromSession(token) { export function requestUserInfoFromSession(token) {
return Instance.call(this).requestUserInfoFromSession(token) return requestRest({
url: '/user/info',
method: 'get',
params: {
token
}
})
.then(evaluateResponse)
} }
/** /**
* Get session info * Get session info
* @param {string} sessionUuid * @param {string} token or session UUID
*/ */
export function getSessionInfo(sessionUuid) { export function requestSessionInfo(token) {
return Instance.call(this).getSession(sessionUuid) return requestRest({
url: '/user/session',
method: 'get',
params: {
token
} }
})
.then(evaluateResponse)
.then(responseSession => {
const { convertSession } = require('@/utils/ADempiere/apiConverts/user.js')
// Logout from server return convertSession(responseSession)
export function logout(sessionUuid) { })
return Instance.call(this).requestLogOut(sessionUuid)
} }
/** /**
* * Logout from server
* @param {string} attributes.sessionUuid * @param {string} token or session UUID
* @param {string} attributes.roleUuid
* @param {string} attributes.organizationUuid
* @param {string} attributes.warehouseUuid
*/ */
// Get User menu from server export function logout(token) {
export function getMenu(sessionUuid) { return requestRest({
return Instance.call(this).requestUserMenuFromSession(sessionUuid) url: '/user/logout',
data: {
token
} }
export function changeRole(attributes) { })
return Instance.call(this).requestChangeRole(attributes) }
/**
* Get User menu from server
* @param {string} sessionUuid
*/
export function requestMenu({
sessionUuid
}) {
return requestRest({
url: '/user/menu',
method: 'get',
params: {
token: sessionUuid
}
})
.then(evaluateResponse)
} }

View File

@ -75,25 +75,22 @@ export default {
}, },
handleCurrentChange(getRecordNotification, val, index, rows) { handleCurrentChange(getRecordNotification, val, index, rows) {
if (val !== null) { if (val !== null) {
let options = {
name: 'ProcessActivity'
}
if (getRecordNotification && getRecordNotification.isReport && val.className !== 'procesActivity') { if (getRecordNotification && getRecordNotification.isReport && val.className !== 'procesActivity') {
this.$router.push({ options = {
name: 'Report Viewer', name: 'Report Viewer',
params: { params: {
processId: getRecordNotification.processId, processId: getRecordNotification.processId,
instanceUuid: getRecordNotification.instanceUuid, instanceUuid: getRecordNotification.instanceUuid,
fileName: getRecordNotification.download fileName: getRecordNotification.download
} }
}).catch(error => {
console.info(`${this.name} Component: ${error.name}, ${error.message}`)
})
} else {
this.$router.push({
name: 'ProcessActivity'
}).catch(error => {
console.info(`${this.name} Component: ${error.name}, ${error.message}`)
})
} }
} }
this.$router.push(options, () => {})
}
}, },
deleteRow(index, rows) { deleteRow(index, rows) {
rows.splice(index, 1) rows.splice(index, 1)

View File

@ -0,0 +1,157 @@
<template>
<div>
<el-card
v-if="isNote"
class="box-card chat-entries-list-card"
:style="{ 'height': getHeightPanelBottom + 'vh' }"
>
<span
slot="header"
class="clearfix chat-entries-card-title"
>
{{ $t('window.containerInfo.notes') }}
</span>
<el-scrollbar wrap-class="scroll-window-log-chat">
<el-timeline>
<el-timeline-item
v-for="(chats, key) in chatList"
:key="key"
:timestamp="translateDate(chats.logDate)"
placement="top"
>
<el-card shadow="hover">
<div v-markdown="chats.characterData" />
</el-card>
</el-timeline-item>
</el-timeline>
</el-scrollbar>
</el-card>
<el-card
class="box-card chat-entry-create-card"
>
<span slot="header" class="clearfix chat-entries-card-title">
{{ $t('window.containerInfo.logWorkflow.addNote') }}
</span>
<el-scrollbar>
<input-chat />
<el-button
icon="el-icon-success"
style="background: #008fd3; float: right"
type="primary"
circle
@click="sendComment()"
/>
</el-scrollbar>
</el-card>
</div>
</template>
<script>
import inputChat from './inputChat'
export default {
name: 'ChatEntries',
components: {
inputChat
},
props: {
tableName: {
type: String,
default: undefined
},
recordId: {
type: Number,
default: undefined
}
},
computed: {
chatList() {
const commentLogs = this.$store.getters.getChatEntries
if (this.isEmptyValue(commentLogs)) {
return commentLogs
}
commentLogs.sort((a, b) => {
const c = new Date(a.logDate)
const d = new Date(b.logDate)
return c - d
})
return commentLogs
},
language() {
return this.$store.getters.language
},
tableNameToSend() {
if (this.isEmptyValue(this.tableName)) {
return this.$route.params.tableName
}
return this.tableName
},
recordIdToSend() {
if (this.isEmptyValue(this.recordId)) {
return this.$route.params.recordId
}
return this.recordId
},
isNote() {
return this.$store.getters.getIsNote
},
getHeightPanelBottom() {
return this.$store.getters.getSplitHeight - 14
}
},
methods: {
sendComment() {
const comment = this.$store.getters.getChatTextLong
if (!this.isEmptyValue(comment)) {
this.$store.dispatch('createChatEntry', {
tableName: this.tableNameToSend,
recordId: this.recordIdToSend,
comment
})
}
},
translateDate(value) {
return this.$d(new Date(value), 'long', this.language)
}
}
}
</script>
<style lang="scss">
.chat-entries-list-card {
// small title of the card
.el-card__header {
max-height: 35px !important;
padding: 10px 20px !important;
}
// brings the card space closer to the timerline
.el-card__body {
padding-left: 0px !important;
}
.el-timeline-item__content {
.el-card {
// remove the right spacing so that it does not overlap with the scroll
margin-right: 20px !important;
// removes excessive card content space from chat logs
.el-card__body {
padding-left: 20px !important;
padding-top: 0px !important;
padding-bottom: 0px !important;
}
}
}
}
.chat-entry-create-card {
// small title of the card
.el-card__header {
max-height: 35px !important;
padding: 10px 20px !important;
}
}
</style>

View File

@ -0,0 +1,68 @@
<template>
<toast-editor
ref="editor"
:initial-value="value"
height="150px"
:options="editorOptions"
@change="onContentChanged"
/>
</template>
<script>
import 'codemirror/lib/codemirror.css'
import '@toast-ui/editor/dist/toastui-editor.css'
import { Editor } from '@toast-ui/vue-editor'
import '@toast-ui/editor/dist/i18n/es-es'
import { getLanguage } from '@/lang'
export default {
components: {
toastEditor: Editor
},
computed: {
editorInstance() {
return this.$refs.editor
},
editorOptions() {
return {
language: this.language,
minHeight: '100px',
usageStatistics: false, // send hostname to google analytics
hideModeSwitch: true
}
},
language() {
const langInCookie = getLanguage()
// https://github.com/nhn/tui.editor/tree/master/apps/editor/src/js/i18n
if (this.isEmptyValue(langInCookie)) {
return 'en-US'
}
return langInCookie.replace('_', '-')
},
value: {
get() {
return this.$store.getters.getChatTextLong
},
set(newValue) {
this.$store.commit('setChatText', newValue)
}
},
markdownValue() {
return this.editorInstance.invoke('getMarkdown')
}
},
watch: {
value(newValue) {
if (this.isEmptyValue(newValue)) {
this.editorInstance.invoke('setMarkdown', '')
}
}
},
methods: {
onContentChanged() {
this.value = this.markdownValue
}
}
}
</script>

View File

@ -1,51 +0,0 @@
<template>
<div>
<el-card
v-if="isNote"
class="box-card"
>
<div slot="header" class="clearfix">
<span>{{ $t('window.containerInfo.notes') }}</span>
</div>
<el-scrollbar wrap-class="scroll-window-log-chat">
<el-timeline>
<el-timeline-item
v-for="(chats, key) in gettersLischat"
:key="key"
:timestamp="translateDate(chats.logDate)"
placement="top"
>
<!-- <field-text-long /> -->
<el-card shadow="hover">
<div>
<div v-markdown="chats.characterData" />
</div>
</el-card>
</el-timeline-item>
</el-timeline>
</el-scrollbar>
</el-card>
<el-card class="box-card">
<div slot="header" class="clearfix">
{{ $t('window.containerInfo.logWorkflow.addNote') }}
</div>
<chat-text-long
v-model="chatNote"
/>
<el-button icon="el-icon-success" style="background: #008fd3; float: right" type="primary" circle @click="sendComment(chatNote)" />
</el-card>
</div>
</template>
<script>
import MixinInfo from './mixinInfo.js'
import chatTextLong from '@/components/ADempiere/Field/chatTextLong'
export default {
name: 'ChatEntries',
components: {
chatTextLong
},
mixins: [MixinInfo]
}
</script>

View File

@ -1,80 +1,11 @@
export default { export default {
name: 'MixinContainerInfo', name: 'MixinContainerInfo',
data() {
return {
currentKey: 100,
typeAction: 0,
chatNote: ''
}
},
computed: { computed: {
gettersLischat() {
const commentLogs = this.$store.getters.getChatEntries
if (this.isEmptyValue(commentLogs)) {
return commentLogs
}
commentLogs.sort((a, b) => {
const c = new Date(a.logDate)
const d = new Date(b.logDate)
return c - d
})
return commentLogs
},
gettersListRecordLogs() {
const changeLog = this.$store.getters.getRecordLogs.recorLogs
return changeLog
},
getIsChangeLog() {
if (this.isEmptyValue(this.gettersListRecordLogs)) {
return false
}
return true
},
getIsChat() {
return this.$store.getters.getIsNote
},
gettersListWorkflow() {
return this.$store.getters.getWorkflow
},
getIsWorkflowLog() {
if (this.isEmptyValue(this.gettersListWorkflow)) {
return false
}
return true
},
language() { language() {
return this.$store.getters.language return this.$store.getters.language
},
isNote() {
return this.$store.getters.getIsNote
} }
}, },
methods: { methods: {
sendComment() {
const chatTextLong = this.$store.getters.getChatTextLong
if (!this.isEmptyValue(chatTextLong)) {
this.$store.dispatch('createChatEntry', {
tableName: this.$route.params.tableName,
recordId: this.$route.params.recordId,
comment: chatTextLong
})
.then(() => {
this.$store.dispatch('setMarkDown', true)
this.$store.dispatch('listChatEntries', {
tableName: this.$route.params.tableName,
recordId: this.$route.params.recordId
})
})
}
},
showkey(key, index) {
if (key === this.currentKey && index === this.typeAction) {
this.currentKey = 1000
} else {
this.currentKey = key
this.typeAction = index
}
},
translateDate(value) { translateDate(value) {
return this.$d(new Date(value), 'long', this.language) return this.$d(new Date(value), 'long', this.language)
} }

View File

@ -16,13 +16,39 @@
<el-card shadow="hover" class="clearfix"> <el-card shadow="hover" class="clearfix">
<div> <div>
{{ listLogs.userName }} {{ listLogs.userName }}
<el-link type="primary" style="float: right;" @click="showkey(key)"> {{ $t('window.containerInfo.changeDetail') }} </el-link> <el-link
type="primary"
style="float: right;"
@click="showkey(key)"
>
{{ $t('window.containerInfo.changeDetail') }}
</el-link>
</div> </div>
<el-collapse-transition> <el-collapse-transition>
<div v-show="(currentKey === key)"> <div v-show="(currentKey === key)">
<span v-for="(list, index) in listLogs.changeLogs" :key="index"> <span v-for="(list, index) in listLogs.changeLogs" :key="index">
<p v-if="list.columnName === 'DocStatus'"><b> {{ list.displayColumnName }} :</b> <strike> <el-tag :type="tagStatus(list.oldValue)"> {{ list.oldDisplayValue }} </el-tag> </strike> <el-tag :type="tagStatus(list.newValue)"> {{ list.newDisplayValue }} </el-tag> </p> <p v-if="list.columnName === 'DocStatus'">
<p v-else><b> {{ list.displayColumnName }} :</b> <strike> <el-link type="danger"> {{ list.oldDisplayValue }} </el-link> </strike> <el-link type="success"> {{ list.newDisplayValue }} </el-link> </p> <b> {{ list.displayColumnName }} :</b>
<strike>
<el-tag :type="tagStatus(list.oldValue)">
{{ list.oldDisplayValue }}
</el-tag>
</strike>
<el-tag :type="tagStatus(list.newValue)">
{{ list.newDisplayValue }}
</el-tag>
</p>
<p v-else>
<b> {{ list.displayColumnName }} :</b>
<strike>
<el-link type="danger">
{{ list.oldDisplayValue }}
</el-link>
</strike>
<el-link type="success">
{{ list.newDisplayValue }}
</el-link>
</p>
</span> </span>
</div> </div>
</el-collapse-transition> </el-collapse-transition>
@ -39,7 +65,15 @@ import MixinInfo from './mixinInfo.js'
export default { export default {
name: 'RecordLogs', name: 'RecordLogs',
mixins: [MixinInfo], mixins: [
MixinInfo
],
data() {
return {
currentKey: 100,
typeAction: 0
}
},
computed: { computed: {
isMobile() { isMobile() {
return this.$store.state.app.device === 'mobile' return this.$store.state.app.device === 'mobile'
@ -55,6 +89,25 @@ export default {
return 'panel-mobile' return 'panel-mobile'
} }
return 'panel' return 'panel'
},
gettersListRecordLogs() {
return this.$store.getters.getRecordLogs.entityLogs
},
getIsChangeLog() {
if (this.isEmptyValue(this.gettersListRecordLogs)) {
return false
}
return true
}
},
methods: {
showkey(key, index) {
if (key === this.currentKey && index === this.typeAction) {
this.currentKey = 1000
} else {
this.currentKey = key
this.typeAction = index
}
} }
} }
} }

View File

@ -32,7 +32,10 @@
width="400" width="400"
trigger="hover" trigger="hover"
> >
<p><b> {{ $t('login.userName') }}:</b> {{ nodeList.userName }} </p> <p>
<b> {{ $t('login.userName') }}:</b>
{{ nodeList.userName }}
</p>
<p v-if="!isEmptyValue(nodeList.textMessage)"> <p v-if="!isEmptyValue(nodeList.textMessage)">
<b> {{ $t('window.containerInfo.logWorkflow.message') }}:</b> <b> {{ $t('window.containerInfo.logWorkflow.message') }}:</b>
{{ nodeList.textMessage }} {{ nodeList.textMessage }}
@ -70,7 +73,18 @@ import MixinInfo from './mixinInfo.js'
export default { export default {
name: 'WorkflowLogs', name: 'WorkflowLogs',
mixins: [MixinInfo] mixins: [MixinInfo],
computed: {
gettersListWorkflow() {
return this.$store.getters.getWorkflow
},
getIsWorkflowLog() {
if (this.isEmptyValue(this.gettersListWorkflow)) {
return false
}
return true
}
}
} }
</script> </script>

View File

@ -69,14 +69,27 @@
<template slot="title"> <template slot="title">
{{ $t('data.exportRecord') }} {{ $t('data.exportRecord') }}
</template> </template>
<el-menu-item v-for="(format, keyFormat) in supportedTypes" :key="keyFormat" :index="keyFormat" @click.native="exportRecord(keyFormat)"> <el-menu-item
v-for="(format, keyFormat) in supportedTypes"
:key="keyFormat"
:index="keyFormat"
@click.native="exportRecord(keyFormat)"
>
{{ format }} {{ format }}
</el-menu-item> </el-menu-item>
</el-submenu> </el-submenu>
<el-menu-item v-show="$route.name === 'Report Viewer'" index="printFormat" @click="redirect"> <el-menu-item
v-show="$route.name === 'Report Viewer'"
index="printFormat"
@click="redirect"
>
{{ $t('components.contextMenuPrintFormatSetup') }} {{ $t('components.contextMenuPrintFormatSetup') }}
</el-menu-item> </el-menu-item>
<el-menu-item v-if="isManageDataRecords" index="refreshData" @click="refreshData"> <el-menu-item
v-if="isManageDataRecords"
index="refreshData"
@click="refreshData"
>
{{ $t('components.contextMenuRefresh') }} {{ $t('components.contextMenuRefresh') }}
</el-menu-item> </el-menu-item>
<el-menu-item index="shareLink" @click="setShareLink"> <el-menu-item index="shareLink" @click="setShareLink">
@ -87,7 +100,11 @@
{{ $t('components.contextMenuActions') }} {{ $t('components.contextMenuActions') }}
</el-menu-item> </el-menu-item>
<el-submenu :disabled="!(isReferecesContent && isLoadedReferences)" class="el-menu-item" index="references"> <el-submenu
:disabled="!(isReferecesContent && isLoadedReferences)"
class="el-menu-item"
index="references"
>
<template slot="title"> <template slot="title">
{{ $t('components.contextMenuReferences') }} {{ $t('components.contextMenuReferences') }}
</template> </template>

View File

@ -1,6 +1,6 @@
import { showNotification } from '@/utils/ADempiere/notification.js' import { showNotification } from '@/utils/ADempiere/notification.js'
import Item from './items' import Item from './items'
import { convertFieldListToShareLink, recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js' import { convertFieldsListToShareLink, recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js'
import { supportedTypes, exportFileFromJson } from '@/utils/ADempiere/exportUtil.js' import { supportedTypes, exportFileFromJson } from '@/utils/ADempiere/exportUtil.js'
import ROUTES from '@/utils/ADempiere/zoomWindow' import ROUTES from '@/utils/ADempiere/zoomWindow'
@ -67,9 +67,7 @@ export default {
downloads: this.$store.getters.getProcessResult.url, downloads: this.$store.getters.getProcessResult.url,
metadataMenu: {}, metadataMenu: {},
recordUuid: this.$route.query.action, recordUuid: this.$route.query.action,
isLoadedReferences: false, isLoadedReferences: false
exportDefault: 'xls',
ROUTES
} }
}, },
computed: { computed: {
@ -111,17 +109,21 @@ export default {
return this.$store.getters.permission_routes return this.$store.getters.permission_routes
}, },
valuesPanelToShare() { valuesPanelToShare() {
let containerUuid = this.containerUuid
if (this.$route.query.action === 'advancedQuery') {
containerUuid = 'table_' + containerUuid
}
return this.$store.getters.getParametersToShare({ return this.$store.getters.getParametersToShare({
containerUuid: this.containerUuid, containerUuid,
isOnlyDisplayed: true, isOnlyDisplayed: true
isAdvancedQuery: this.$route.query.action === 'advancedQuery'
}) })
}, },
getterFieldList() { getterFieldsList() {
return this.$store.getters.getFieldsListFromPanel(this.containerUuid) return this.$store.getters.getFieldsListFromPanel(this.containerUuid)
}, },
getterFieldListHeader() { getterFieldsListHeader() {
const header = this.getterFieldList.filter(fieldItem => { const header = this.getterFieldsList.filter(fieldItem => {
const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic
if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) { if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) {
return fieldItem.name return fieldItem.name
@ -131,8 +133,8 @@ export default {
return fieldItem.name return fieldItem.name
}) })
}, },
getterFieldListValue() { getterFieldsListValue() {
const value = this.getterFieldList.filter(fieldItem => { const value = this.getterFieldsList.filter(fieldItem => {
const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic
if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) { if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) {
return fieldItem return fieldItem
@ -275,14 +277,15 @@ export default {
console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`) console.warn(`Error getting data list tab. Message: ${error.message}, code ${error.code}.`)
}) })
} else if (this.panelType === 'browser') { } else if (this.panelType === 'browser') {
const fieldsEmpty = this.$store.getters.getFieldListEmptyMandatory({ const fieldsEmpty = this.$store.getters.getFieldsListEmptyMandatory({
containerUuid: this.containerUuid, containerUuid: this.containerUuid,
fieldsList: this.getterFieldList fieldsList: this.getterFieldsList
}) })
if (fieldsEmpty.length) { if (fieldsEmpty.length) {
this.$message({ this.$message({
message: this.$t('notifications.mandatoryFieldMissing') + fieldsEmpty, message: this.$t('notifications.mandatoryFieldMissing') + fieldsEmpty,
type: 'info' type: 'info',
showClose: true
}) })
} else { } else {
this.$store.dispatch('getBrowserSearch', { this.$store.dispatch('getBrowserSearch', {
@ -319,8 +322,8 @@ export default {
} }
}, },
exportRecord(fotmatToExport) { exportRecord(fotmatToExport) {
const tHeader = this.getterFieldListHeader const tHeader = this.getterFieldsListHeader
const filterVal = this.getterFieldListValue const filterVal = this.getterFieldsListValue
let list = [] let list = []
if (this.panelType === 'window') { if (this.panelType === 'window') {
list = this.getDataRecord list = this.getDataRecord
@ -355,7 +358,9 @@ export default {
this.actions = this.metadataMenu.actions this.actions = this.metadataMenu.actions
// TODO: Add store attribute to avoid making repeated requests // TODO: Add store attribute to avoid making repeated requests
if (this.panelType === 'window') { let isChangePrivateAccess = true
if (this.isReferecesContent) {
isChangePrivateAccess = false
if (!this.isEmptyValue(this.$route.params.tableName)) { if (!this.isEmptyValue(this.$route.params.tableName)) {
this.$store.dispatch('getPrivateAccessFromServer', { this.$store.dispatch('getPrivateAccessFromServer', {
tableName: this.$route.params.tableName, tableName: this.$route.params.tableName,
@ -371,6 +376,7 @@ export default {
} }
const processAction = this.actions.find(item => { const processAction = this.actions.find(item => {
// TODO: Compare with 'action' attribute and not with 'name' (this change with language)
if (item.name === 'Procesar Orden' || (item.name === 'Process Order')) { if (item.name === 'Procesar Orden' || (item.name === 'Process Order')) {
return item return item
} }
@ -380,24 +386,32 @@ export default {
if (this.actions && this.actions.length) { if (this.actions && this.actions.length) {
this.actions.forEach(itemAction => { this.actions.forEach(itemAction => {
if (this.$route.meta.type === 'report' && itemAction.action === 'startProcess') { const { action } = itemAction
if (this.$route.meta.type === 'report' && action === 'startProcess') {
itemAction.reportExportType = 'html' itemAction.reportExportType = 'html'
} }
// if no exists set prop with value // if no exists set prop with value
itemAction.disabled = false itemAction.disabled = false
if ((this.$route.name !== 'Report Viewer' && itemAction.action === 'changeParameters') || if ((this.$route.name !== 'Report Viewer' && action === 'changeParameters') ||
(this.$route.meta.type === 'process' && itemAction.type === 'summary')) { (this.$route.meta.type === 'process' && itemAction.type === 'summary')) {
itemAction.disabled = true itemAction.disabled = true
} }
if (this.$route.meta.type === 'window') { if (this.$route.meta.type === 'window') {
if (this.recordUuid === 'create-new' || !this.isInsertRecord) { if (isChangePrivateAccess) {
itemAction.disabled = true if (action === 'lockRecord') {
itemAction.hidden = false
} else if (action === 'unlockRecord') {
itemAction.hidden = true
} }
}
// rollback // rollback
if (itemAction.action === 'undoModifyData') { if (itemAction.action === 'undoModifyData') {
itemAction.disabled = Boolean(!this.getDataLog && !this.getOldRouteOfWindow) itemAction.disabled = Boolean(!this.getDataLog && !this.getOldRouteOfWindow)
} else if (this.recordUuid === 'create-new' || !this.isInsertRecord) {
itemAction.disabled = true
} }
} }
}) })
@ -444,10 +458,12 @@ export default {
query: { query: {
...this.getOldRouteOfWindow.query ...this.getOldRouteOfWindow.query
} }
}).catch(error => { }, () => {})
console.info(`Context Menu Mixin: ${error.name}, ${error.message}`)
})
} else { } else {
if (action.action === 'setDefaultValues' && this.$route.query.action === 'create-new') {
return
}
this.$store.dispatch(action.action, { this.$store.dispatch(action.action, {
parentUuid: this.parentUuid, parentUuid: this.parentUuid,
containerUuid: this.containerUuid, containerUuid: this.containerUuid,
@ -472,7 +488,7 @@ export default {
if (this.lastParameter !== undefined) { if (this.lastParameter !== undefined) {
containerParams = this.lastParameter containerParams = this.lastParameter
} }
const fieldsNotReady = this.$store.getters.getFieldListEmptyMandatory({ const fieldsNotReady = this.$store.getters.getFieldsListEmptyMandatory({
containerUuid: containerParams containerUuid: containerParams
}) })
@ -590,13 +606,12 @@ export default {
// windowUuid: this.parentUuid, // windowUuid: this.parentUuid,
tabParent: 0 tabParent: 0
} }
}).catch(error => { }, () => {})
console.info(`Context Menu Mixin: ${error.name}, ${error.message}`)
})
} else { } else {
this.$message({ this.$message({
type: 'error', type: 'error',
message: this.$t('notifications.noRoleAccess') message: this.$t('notifications.noRoleAccess'),
showClose: true
}) })
} }
} }
@ -604,7 +619,7 @@ export default {
setShareLink() { setShareLink() {
let shareLink = this.panelType === 'window' || window.location.href.includes('?') ? `${window.location.href}&` : `${window.location.href}?` let shareLink = this.panelType === 'window' || window.location.href.includes('?') ? `${window.location.href}&` : `${window.location.href}?`
if (this.$route.name === 'Report Viewer') { if (this.$route.name === 'Report Viewer') {
const processParameters = convertFieldListToShareLink(this.processParametersExecuted) const processParameters = convertFieldsListToShareLink(this.processParametersExecuted)
const reportFormat = this.$store.getters.getReportType const reportFormat = this.$store.getters.getReportType
shareLink = this.$store.getters.getTempShareLink shareLink = this.$store.getters.getTempShareLink
if (String(processParameters).length) { if (String(processParameters).length) {
@ -661,15 +676,14 @@ export default {
}) })
}, },
redirect() { redirect() {
const { uuid: name, tabParent } = ROUTES.PRINT_FORMAT_SETUP_WINDOW
this.$router.push({ this.$router.push({
name: ROUTES.PRINT_FORMAT_SETUP_WINDOW.uuid, name,
query: { query: {
action: this.getReportDefinition.output.printFormatUuid, action: this.getReportDefinition.output.printFormatUuid,
tabParent: ROUTES.PRINT_FORMAT_SETUP_WINDOW.tabParent tabParent
} }
}).catch(error => { }, () => {})
console.info(`Context Menu Mixin: ${error.name}, ${error.message}`)
})
}, },
validatePrivateAccess({ isLocked, tableName, recordId }) { validatePrivateAccess({ isLocked, tableName, recordId }) {
if (this.isPersonalLock) { if (this.isPersonalLock) {

View File

@ -54,7 +54,7 @@ export default {
query: { query: {
tabParent: 0 tabParent: 0
} }
}) }, () => {})
} }
} }
} }

View File

@ -107,9 +107,7 @@ export default {
action: 'criteria', action: 'criteria',
tabParent tabParent
} }
}).catch(error => { }, () => {})
console.info(`Dashboard/docstatus Component: ${error.name}, ${error.message}`)
})
} else { } else {
this.$message({ this.$message({
type: 'error', type: 'error',

View File

@ -24,7 +24,7 @@ export default {
handleClick(row) { handleClick(row) {
const viewSearch = this.recursiveTreeSearch({ const viewSearch = this.recursiveTreeSearch({
treeData: this.permissionRoutes, treeData: this.permissionRoutes,
attributeValue: row.windowUuid, attributeValue: row.referenceUuid,
attributeName: 'meta', attributeName: 'meta',
secondAttribute: 'uuid', secondAttribute: 'uuid',
attributeChilds: 'children' attributeChilds: 'children'
@ -46,9 +46,7 @@ export default {
action: recordUuid, action: recordUuid,
tabParent tabParent
} }
}).catch(error => { }, () => {})
console.info(`Dashboard ${this.name}: ${error.name}, ${error.message}`)
})
} else { } else {
this.$message({ this.$message({
type: 'error', type: 'error',

View File

@ -35,13 +35,15 @@
</template> </template>
<script> <script>
import { getRecentItems as getRecentItemsFromServer } from '@/api/ADempiere/dashboard/dashboard' import { requestListRecentItems } from '@/api/ADempiere/dashboard/dashboard'
import { convertAction } from '@/utils/ADempiere/dictionaryUtils' import { convertAction } from '@/utils/ADempiere/dictionaryUtils'
import mixinDashboard from '@/components/ADempiere/Dashboard/mixinDashboard.js' import mixinDashboard from '@/components/ADempiere/Dashboard/mixinDashboard.js'
export default { export default {
name: 'RecentItems', name: 'RecentItems',
mixins: [mixinDashboard], mixins: [
mixinDashboard
],
data() { data() {
return { return {
recentItems: [], recentItems: [],
@ -54,6 +56,12 @@ export default {
return this.filterResult(this.search) return this.filterResult(this.search)
} }
return this.recentItems return this.recentItems
},
userUuid() {
return this.$store.getters['user/getUserUuid']
},
roleUuid() {
return this.$store.getters['user/getRole'].uuid
} }
}, },
mounted() { mounted() {
@ -67,10 +75,16 @@ export default {
methods: { methods: {
getRecentItems({ pageToken, pageSize }) { getRecentItems({ pageToken, pageSize }) {
return new Promise(resolve => { return new Promise(resolve => {
getRecentItemsFromServer({ pageToken, pageSize }) requestListRecentItems({
userUuid: this.userUuid,
roleUuid: this.roleUuid,
pageToken,
pageSize
})
.then(response => { .then(response => {
const recentItems = response.recentItemsList.map(item => { const recentItems = response.recentItemsList.map(item => {
const actionConverted = convertAction(item.action) const actionConverted = convertAction(item.action)
return { return {
...item, ...item,
action: actionConverted.name, action: actionConverted.name,

View File

@ -87,7 +87,9 @@ export default {
getFavoritesList() { getFavoritesList() {
const userUuid = this.$store.getters['user/getUserUuid'] const userUuid = this.$store.getters['user/getUserUuid']
return new Promise(resolve => { return new Promise(resolve => {
getFavoritesFromServer({ userUuid }) getFavoritesFromServer({
userUuid
})
.then(response => { .then(response => {
const favorites = response.favoritesList.map(favoriteElement => { const favorites = response.favoritesList.map(favoriteElement => {
const actionConverted = convertAction(favoriteElement.action) const actionConverted = convertAction(favoriteElement.action)
@ -131,9 +133,7 @@ export default {
action: param, action: param,
tabParent: 0 tabParent: 0
} }
}).catch(error => { }, () => {})
console.info(`Dashboard/userfavorites Component: ${error.name}, ${error.message}`)
})
} else { } else {
this.$message({ this.$message({
type: 'error', type: 'error',

View File

@ -0,0 +1,720 @@
import FieldDefinition from '@/components/ADempiere/Field'
import FilterColumns from '@/components/ADempiere/DataTable/filterColumns'
import FixedColumns from '@/components/ADempiere/DataTable/fixedColumns'
import TableContextMenu from '@/components/ADempiere/DataTable/menu/tableContextMenu'
import TableMainMenu from '@/components/ADempiere/DataTable/menu'
import IconElement from '@/components/ADempiere/IconElement'
import { formatField } from '@/utils/ADempiere/valueFormat'
import MainPanel from '@/components/ADempiere/Panel'
import { sortFields } from '@/utils/ADempiere/dictionaryUtils'
import { FIELDS_DECIMALS, FIELDS_QUANTITY, FIELDS_READ_ONLY_FORM } from '@/utils/ADempiere/references'
import { fieldIsDisplayed } from '@/utils/ADempiere'
import evaluator from '@/utils/ADempiere/evaluator'
import TableMixin from './mixin/tableMixin.js'
import TableMixinSort from './mixin/mixinTableSort.js'
import CustomPagination from '@/components/ADempiere/Pagination'
export default {
name: 'DataTable',
components: {
CustomPagination,
FieldDefinition,
FilterColumns,
FixedColumns,
IconElement,
MainPanel,
TableContextMenu,
TableMainMenu
},
mixins: [
TableMixin,
TableMixinSort
],
props: {
// Show check from selection row
isTableSelection: {
type: Boolean,
default: true
},
// Show check from selection row, send to panel form
isShowedPanelRecord: {
type: Boolean,
default: false
}
},
data() {
const activeName = []
// TODO: Manage attribute with vuex store in window module
if (this.isParent && this.$route.query.action && this.$route.query.action === 'advancedQuery') {
activeName.push('PanelAdvancedQuery')
}
return {
topContextualMenu: 0,
leftContextualMenu: 0,
currentRowMenu: {},
currentRow: null,
currentTable: 0,
visible: this.getShowContextMenuTable,
searchTable: '', // text from search
defaultMaxPagination: 50,
activeName,
rowStyle: {
height: '52px'
},
uuidCurrentRecordSelected: '',
showTableSearch: false
}
},
computed: {
isShowedContextMenu() {
if (this.isParent) {
return this.getShowContextMenuTable
}
return this.getShowContextMenuTabChildren
},
getMenuTable() {
const process = this.$store.getters.getContextMenu(this.containerUuid)
if (process && !this.isEmptyValue(process.actions)) {
return process.actions.filter(menu => {
if (menu.type === 'process' || menu.type === 'application') {
return menu
}
})
}
return []
},
getShowContextMenuTable() {
return this.$store.getters.getShowContextMenuTable
},
getShowContextMenuTabChildren() {
return this.$store.getters.getShowContextMenuTabChildren
},
panelMetadata() {
return this.$store.getters.getPanel(this.containerUuid)
},
isLoadedPanel() {
const panelMetadata = this.$store.getters.getPanel('table_' + this.containerUuid)
if (!this.isEmptyValue(panelMetadata)) {
return true
}
return false
},
isShowedTotals() {
return this.panelMetadata.isShowedTotals
},
isShowOptionalColumns() {
return this.panelMetadata.isShowedTableOptionalColumns
},
totalRecords() {
return this.getterDataRecordsAndSelection.recordCount
},
pageNumber() {
return this.getterDataRecordsAndSelection.pageNumber
},
isLoaded() {
return !this.getterDataRecordsAndSelection.isLoaded
},
fieldsIsDisplayed() {
return this.$store.getters.getFieldsIsDisplayed(this.containerUuid)
},
getterIsShowedCriteria() {
const browser = this.$store.getters.getBrowser(this.containerUuid)
if (browser) {
return browser.isShowedCriteria
}
return false
},
getHeightPanelBottom() {
return this.$store.getters.getSplitHeight - 25
},
getterHeight() {
return this.$store.getters.getHeigth
},
tableHeaderStyle() {
if (this.isParent) {
if (!this.isEmptyValue(this.activeName)) {
return {
height: '55%',
overflow: 'auto'
}
}
return {
height: '17%',
overflow: 'hidden'
}
}
return {
height: '35px'
}
},
getHeigthTable() {
let totalRow = 0
// to refresh height table if changed isShowedTotals
if (this.isShowedTotals) {
totalRow = 5
}
if (this.isPanelWindow) {
// table record navigation
if (this.isParent) {
if (this.isEmptyValue(this.activeName)) {
return this.getterHeight - 210 - totalRow
}
// panel advanced query is showed
return this.getterHeight - 420 - totalRow
}
// tabs children
if (totalRow) {
totalRow = 1
}
return (this.getHeightPanelBottom - 5 - totalRow) + 'vh'
} else if (this.panelType === 'browser') {
// open browser criteria
if (this.getterIsShowedCriteria) {
// showed some field in panel query criteria
if (this.fieldsIsDisplayed.isDisplayed) {
return this.getterHeight - 495 - totalRow
}
return this.getterHeight - 415 - totalRow
}
return this.getterHeight - 290 - totalRow
}
return this.getterHeight - 300 - totalRow
},
fieldsList() {
const panelMetadata = this.panelMetadata
if (panelMetadata && panelMetadata.fieldsList) {
if ((this.panelType === 'window' && this.isParent) || this.panelType === 'browser') {
let orderBy = 'seqNoGrid'
if (this.panelType === 'browser') {
orderBy = 'sequence'
}
return this.sortFields({
fieldsList: panelMetadata.fieldsList,
orderBy
})
}
return panelMetadata.fieldsList
}
return []
},
isLoadPanel() {
const panelMetadata = this.panelMetadata
if (panelMetadata && panelMetadata.fieldsList) {
return true
}
return false
},
preferenceClientId() {
if (this.isPanelWindow) {
return this.$store.getters.getPreferenceClientId
}
return undefined
},
shorcutKey() {
return {
f6: ['f6'],
ctrlf: ['ctrl', 'f']
}
},
keyUp() {
if (this.currentTable < 1) {
return this.currentTable
}
return this.currentTable - 1
},
keyDow() {
const maxDown = this.recordsData.length - 1
if (maxDown === this.currentTable) {
return this.currentTable
}
return this.currentTable + 1
}
},
watch: {
visible(value) {
if (value) {
document.body.addEventListener('click', this.closeMenu)
} else {
document.body.removeEventListener('click', this.closeMenu)
}
}
},
created() {
this.getPanel()
},
mounted() {
if (this.isTableSelection) {
this.toggleSelection(this.getDataSelection)
}
},
methods: {
sortFields,
actionAdvancedQuery() {
const activeNames = []
if (!this.activeName.length) {
activeNames.push('PanelAdvancedQuery')
if (this.isParent) {
const { isShowedRecordNavigation } = this.$store.getters.getWindow(this.parentUuid)
if (!isShowedRecordNavigation) {
this.$store.dispatch('changeWindowAttribute', {
parentUuid: this.parentUuid, // act as parentUuid
attributeName: 'isShowedRecordNavigation',
attributeValue: true
})
}
}
}
this.activeName = activeNames
},
setCurrent(row) {
this.$refs.multipleTable.setCurrentRow(row)
},
theAction(event) {
switch (event.srcKey) {
case 'up':
this.currentTable = this.keyUp
break
case 'down':
this.currentTable = this.keyDow
break
}
this.handleRowClick(this.recordsData[this.currentTable])
return this.setCurrent(this.recordsData[this.currentTable])
},
block() {
return false
},
rowMenu(row, column, event) {
const menuMinWidth = 105
const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
const offsetWidth = this.$el.offsetWidth // container width
const maxLeft = offsetWidth - menuMinWidth // left boundary
const left = event.clientX - offsetLeft + 15 // 15: margin right
this.leftContextualMenu = left
if (left > maxLeft) {
this.leftContextualMenu = maxLeft
}
const offsetTop = this.$el.getBoundingClientRect().top
let top = event.clientY - offsetTop
if (this.panelType === 'browser' && this.panelMetadata.isShowedCriteria) {
top = event.clientY - 200
}
this.topContextualMenu = top
this.currentRowMenu = row
this.visible = true
// TODO: Verify use
this.$store.dispatch('showMenuTable', {
isShowedTable: this.isParent
})
this.$store.dispatch('showMenuTabChildren', {
isShowedTabChildren: !this.isParent
})
},
headerLabel(field) {
if (field.isMandatory || field.isMandatoryFromLogic) {
return '* ' + field.name
}
return field.name
},
/**
* @param {object} row, row data
* @param {object} field, field with attributes
*/
displayedValue(row, field) {
const { columnName, componentPath, displayColumnName, displayType } = field
let valueToShow
switch (componentPath) {
case 'FieldDate':
case 'FieldTime': {
let cell = row[columnName]
if (this.typeValue(cell) === 'DATE') {
cell = cell.getTime()
}
// replace number timestamp value for date
valueToShow = formatField(cell, displayType)
break
}
case 'FieldNumber':
if (this.isEmptyValue(row[columnName])) {
valueToShow = undefined
break
}
valueToShow = this.formatNumber({
displayType,
number: row[columnName]
})
break
case 'FieldSelect':
valueToShow = row[displayColumnName]
if (this.isEmptyValue(valueToShow) && row[columnName] === 0) {
valueToShow = field.defaultValue
break
}
break
case 'FieldYesNo':
// replace boolean true-false value for 'Yes' or 'Not' ('Si' or 'No' for spanish)
valueToShow = row[columnName]
? this.$t('components.switchActiveText')
: this.$t('components.switchInactiveText')
break
default:
valueToShow = row[columnName]
break
}
return valueToShow
},
rowCanBeEdited(record, fieldAttributes) {
if (!this.isParent) {
if (this.isPanelWindow) {
// getter with context
if (this.isReadOnlyParent) {
return false
}
// if record is IsActive, Processed, Processing
if (this.isReadOnlyRow(record, fieldAttributes)) {
return false
}
}
// if isReadOnly, isReadOnlyFromLogic
if (this.isReadOnlyCell(record, fieldAttributes)) {
return false
}
if (record.isEdit) {
return true
}
}
return false
},
isReadOnlyRow(row, field) {
// evaluate context
if (this.preferenceClientId !== parseInt(row.AD_Client_ID, 10)) {
return true
}
if (fieldIsDisplayed(field)) {
// 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 { columnName, valueIsReadOnlyForm } = fieldReadOnlyForm
// compare if is same key
return field.columnName !== columnName &&
// compare if is same value
row[columnName] === valueIsReadOnlyForm
}
}
return false
},
isReadOnlyCell(row, field) {
// TODO: Add support to its type fields
if (['FieldImage', 'FieldBinary'].includes(field.componentPath)) {
return true
}
const isUpdateableAllFields = field.isReadOnly || field.isReadOnlyFromLogic
if (this.isPanelWindow) {
const panelMetadata = this.panelMetadata
if (field.columnName === panelMetadata.linkColumnName ||
field.columnName === panelMetadata.fieldLinkColumnName) {
return true
}
// edit mode is diferent to create new
const editMode = !this.isEmptyValue(row.UUID)
return (!field.isUpdateable && editMode) || (isUpdateableAllFields || field.isReadOnlyFromForm)
} else if (this.panelType === 'browser') {
// browser result
return field.isReadOnly
}
// other type of panels (process/reports/forms)
return isUpdateableAllFields
},
callOffNewRecord() {
this.recordsData.shift()
},
tableRowClassName({ row, rowIndex }) {
if (row.isNew && rowIndex === 0) {
return 'warning-row'
}
return ''
},
addNewRow() {
if (this.newRecordsQuantity <= 0) {
this.$store.dispatch('addNewRow', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
fieldsList: this.fieldsList,
isEdit: true,
isSendServer: false
})
this.$refs.multipleTable.$refs.bodyWrapper.scrollTop = 0
} else {
const fieldsEmpty = this.$store.getters.getFieldsListEmptyMandatory({
containerUuid: this.containerUuid
})
this.$message({
message: this.$t('notifications.mandatoryFieldMissing') + fieldsEmpty,
type: 'info'
})
}
},
async setFocus() {
return new Promise(resolve => {
const fieldFocus = this.fieldsList.find(itemField => {
if (Object.prototype.hasOwnProperty.call(this.$refs, itemField.columnName)) {
if (fieldIsDisplayed(itemField) && !itemField.isReadOnly && itemField.isUpdateable) {
return true
}
}
})
this.$refs[fieldFocus.columnName][0].focusField()
resolve()
})
},
/**
* @param {object} field
*/
cellClass(field) {
let classReturn = ''
if (field.isReadOnly) {
classReturn += ' cell-no-edit '
}
if (field.componentPath === 'FieldNumber') {
classReturn += ' cell-align-right '
}
// return 'cell-edit'
return classReturn
},
/**
* Select or unselect rows
* USE ONLY MOUNTED
*/
toggleSelection(rows) {
if (rows) {
rows.forEach(row => {
this.$refs.multipleTable.toggleRowSelection(row)
})
} else {
this.$refs.multipleTable.clearSelection()
}
},
confirmEdit(row) {
const fieldsEmpty = this.$store.getters.getFieldsListEmptyMandatory({
containerUuid: this.containerUuid,
row
})
if (row.isNew) {
row.isEdit = true
this.$message({
message: this.$t('notifications.mandatoryFieldMissing') + fieldsEmpty,
type: 'info'
})
return
}
if (row.isEdit && fieldsEmpty) {
row.isEdit = false
this.$message({
message: this.$t('notifications.mandatoryFieldMissing') + fieldsEmpty,
type: 'info'
})
return
}
row.isEdit = false
},
handleRowClick(row, column, event) {
this.currentTable = this.recordsData.findIndex(item => item.UUID === row.UUID)
if (this.isShowedPanelRecord && this.isParent) {
if (this.uuidCurrentRecordSelected !== row.UUID) {
this.uuidCurrentRecordSelected = row.UUID
// disabled rollback when change route
this.$store.dispatch('setDataLog', {})
}
const tableName = this.panelMetadata.tableName
this.$router.push({
name: this.$route.name,
query: {
...this.$route.query,
action: row.UUID
},
params: {
...this.$router.params,
tableName,
recordId: row[`${tableName}_ID`]
}
}, () => {})
this.$store.commit('setCurrentRecord', row)
} else {
if (!row.isEdit) {
row.isEdit = true
/*
const inSelection = this.getDataSelection.some(item => {
return JSON.stringify(item) === JSON.stringify(row)
})
if (inSelection) {
row.isEdit = true
}
*/
}
}
},
handleRowDblClick(row, column, event) {
if (!this.isShowedPanelRecord) {
this.confirmEdit(row)
}
},
handleSelection(rowsSelection, rowSelected) {
this.$store.dispatch('setSelection', {
containerUuid: this.containerUuid,
selection: rowsSelection
})
},
handleSelectionAll(rowsSelection) {
this.$store.dispatch('setSelection', {
containerUuid: this.containerUuid,
selection: rowsSelection
})
},
filterResult() {
const data = this.recordsData.filter(rowItem => {
if (this.searchTable.trim().length) {
let find = false
Object.keys(rowItem).forEach(key => {
if (String(rowItem[key]).toLowerCase().includes(String(this.searchTable).toLowerCase())) {
find = true
return find
}
})
return find
}
return true
})
return data
},
/**
* Verify is displayed field in column table
*/
isDisplayed(field) {
const isDisplayed = field.isDisplayed &&
field.isDisplayedFromLogic &&
field.isShowedTableFromUser &&
!field.isKey
// Verify for displayed and is active
return field.isActive && isDisplayed
},
/**
* Get the tab object with all its attributes as well as the fields it contains
*/
getPanel() {
// get panel from server only window and tab children
if (this.isPanelWindow && !this.isParent && !this.panelMetadata) {
this.$store.dispatch('getPanelAndFields', {
containerUuid: this.containerUuid,
parentUuid: this.parentUuid,
panelType: this.panelType
}).catch(error => {
console.warn(`Fields List Load Error ${error.code}: ${error.message}.`)
})
}
},
/**
* @param {array} columns
* @param {array} data
*/
getSummaries({ columns, data }) {
const sums = []
if (!this.isShowedTotals) {
return
}
const fieldsList = this.fieldsList
columns.forEach((columnItem, index) => {
if (index === 0) {
sums[index] = 'Σ'
return
}
const field = fieldsList.find(fieldItem => fieldItem.columnName === columnItem.property)
const { displayType } = field
if (!FIELDS_QUANTITY.includes(displayType)) {
sums[index] = ''
return
}
const values = this.getDataSelection.map(item => Number(item[columnItem.property]))
if (values.every(value => isNaN(value))) {
sums[index] = 0
} else {
const total = values.reduce((prev, curr) => {
const value = Number(curr)
if (!isNaN(value)) {
return prev + curr
}
return prev
}, 0)
sums[index] = this.formatNumber({
displayType,
number: total
})
}
})
return sums
},
formatNumber({ displayType, number }) {
let fixed = 0
// Amount, Costs+Prices, Number
if (FIELDS_DECIMALS.includes(displayType)) {
fixed = 2
}
return new Intl.NumberFormat().format(number.toFixed(fixed))
},
handleChangePage(newPage) {
this.$store.dispatch('setPageNumber', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
pageNumber: newPage,
panelType: this.panelType
})
},
click() {
this.showTableSearch = !this.showTableSearch
if (this.showTableSearch) {
this.$refs.headerSearchInput && this.$refs.headerSearchInput.focus()
}
},
getFieldDefinition(fieldDefinition, row) {
let styleSheet = ''
if (fieldDefinition && (!this.isEmptyValue(fieldDefinition.id) || fieldDefinition.conditions.length)) {
fieldDefinition.conditions.forEach(condition => {
const columns = evaluator.parseDepends(condition.condition)
let conditionLogic = condition.condition
columns.forEach(column => {
conditionLogic = conditionLogic.replace(/@/g, '')
conditionLogic = conditionLogic.replace(column, row[column])
conditionLogic = evaluator.evaluateLogic({
logic: conditionLogic
})
})
if (conditionLogic && condition.isActive) {
styleSheet = condition.styleSheet
}
})
}
return styleSheet
}
}
}

View File

@ -0,0 +1,132 @@
// used in cell type number
td.cell-align-right, .cell-align-right {
text-align: right !important;
}
// options to record with contextual menu
.contextual-menu {
margin: 0;
background: #fff;
z-index: 3000;
position: absolute;
list-style-type: none;
padding: 5px 0;
border-radius: 4px;
font-size: 12px;
font-weight: 400;
color: #333;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
li {
margin: 0;
padding: 7px 16px;
cursor: pointer;
&:hover {
background: #eee;
}
}
}
.el-submenu__title {
border-bottom: 0px !important;
color: #303133;
}
// .el-menu.el-menu--horizontal {
// border-bottom: solid 0px transparent !important;
// }
// Quick options menu (more options in line and center)
ul.menu-table > .el-submenu {
height: 39px !important;
line-height: 39px !important;
padding: 0px;
border: 0px;
}
ul.menu-table > .el-submenu > .el-submenu__title {
line-height: 39px !important;
height: 39px !important;
padding: 0px;
border: 0px;
}
.panel-expand {
float: right;
padding-right: 40px;
display: flex;
line-height: 39px !important;
}
// .el-collapse {
// border-top: 1px solid #e6ebf5;
// border-bottom: 1px solid #e6ebf5;
// overflow: hidden;
// width: 100%;
// }
// if advanced query is open, show in vertical
.collapse_item_wrap {
min-height: 180px;
max-height: 180px;
will-change: height;
background-color: #fff;
overflow: auto;
-webkit-box-sizing: border-box;
box-sizing: border-box;
border-bottom: 1px solid #e6ebf5;
}
.el-table .warning-row {
background: rgba(161, 250, 223, 0.945);
}
.el-table .success-row {
background: #f0f9eb;
}
.el-table > .cell, .el-table .cell {
-webkit-box-sizing: border-box;
box-sizing: border-box;
overflow: hidden;
max-height: 41px;
text-overflow: ellipsis;
white-space: nowrap;
word-break: break-all;
line-height: 23px;
padding-left: 10px;
padding-right: 10px;
}
.el-table .cell {
max-height: 50px;
}
// .tr.current-row > td {
// background-color: initial !important;
// /* background-color: #e8f4ff; */
// }
// .hover-row > tr {
// background-color: initial !important;
// }
// .hover-row > td {
// background-color: initial !important;
// }
// .header-table-records {
// height: 45px !important;
// padding: 0 !important;
// }
// .icon-mobile {
// padding-right: 5%;
// }
.el-table th, .el-table td {
padding: 12px 0;
min-width: 0;
height: 64px;
max-height: 407px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
text-overflow: ellipsis;
vertical-align: middle;
position: relative;
text-align: left;
}

View File

@ -0,0 +1,104 @@
// style in cursor if cell is no edit
.cell-no-edit {
cursor: not-allowed !important;
}
.cell-edit {
cursor: pointer !important;
}
.field-optional {
margin: 3px 10px;
float: right;
}
// Local search input
.local-search-container {
font-size: 0 !important;
float: right;
color: #5a5e66;
height: 39px !important;
line-height: 39px !important;
.search-icon {
cursor: pointer;
font-size: 18px;
vertical-align: middle;
}
.header-search-input {
transition: width 0.2s;
width: 0 !important;
overflow: hidden;
background: transparent;
border-radius: 0;
display: inline-block;
vertical-align: middle;
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;
padding-right: 0;
box-shadow: none !important;
border-bottom: 1px solid #d9d9d9;
vertical-align: middle;
}
}
&.show {
.header-search-input {
width: 190px !important;
margin-left: 10px;
}
}
&.mobile {
.header-search-input {
width: 120px !important;
margin-left: 5px;
}
}
}
.table-root {
padding-right: 0px;
.table-footer {
bottom: 0px;
float: right;
text-align: right;
padding: 10px;
}
}
// Quick options menu (new record, fixed columns...)
.menu-table {
width: 75px;
float: right;
height: 39px !important;
}
.menu-table-mobile {
height: 39px !important;
width: 35px;
float: right;
}
.el-table__header-wrapper {
/* totals or summary row */
.el-table__footer-wrapper {
overflow: auto;
/* background: black; */
}
}
// with mouse change color to current row
.el-table-row {
.hover-row {
background-color: black;
}
.current-row {
.hover-row {
background-color: initial !important;
}
}
}

View File

@ -1,6 +1,6 @@
<template> <template>
<el-select <el-select
v-model="getterFieldListShowed" v-model="fieldsListShowed"
:filterable="!isMobile" :filterable="!isMobile"
:placeholder="$t('components.filterableItems')" :placeholder="$t('components.filterableItems')"
multiple multiple
@ -10,7 +10,7 @@
class="select" class="select"
> >
<el-option <el-option
v-for="(item, key) in getterFieldListAvailable" v-for="(item, key) in fieldsListAvailable"
:key="key" :key="key"
:label="item.name" :label="item.name"
:value="item.columnName" :value="item.columnName"
@ -31,20 +31,20 @@ export default {
isMobile() { isMobile() {
return this.$store.state.app.device === 'mobile' return this.$store.state.app.device === 'mobile'
}, },
getterFieldList() { fieldsList() {
return this.$store.getters.getFieldsListFromPanel(this.containerUuid) return this.$store.getters.getFieldsListFromPanel(this.containerUuid)
}, },
// available fields // available fields
getterFieldListAvailable() { fieldsListAvailable() {
return this.getterFieldList.filter(fieldItem => { return this.fieldsList.filter(fieldItem => {
const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic
return fieldItem.isActive && isDisplayed && !fieldItem.isKey return fieldItem.isActive && isDisplayed && !fieldItem.isKey
}) })
}, },
getterFieldListShowed: { fieldsListShowed: {
get: function() { get() {
// columns showed // columns showed
return this.getterFieldList.filter(itemField => { return this.fieldsList.filter(itemField => {
if (itemField.isShowedTableFromUser && (itemField.isDisplayed || itemField.isDisplayedFromLogic) && !itemField.isKey) { if (itemField.isShowedTableFromUser && (itemField.isDisplayed || itemField.isDisplayedFromLogic) && !itemField.isKey) {
return true return true
} }
@ -52,7 +52,7 @@ export default {
return itemField.columnName return itemField.columnName
}) })
}, },
set: function(selecteds) { set(selecteds) {
// set columns to show/hidden in vuex store // set columns to show/hidden in vuex store
this.addField(selecteds) this.addField(selecteds)
} }

View File

@ -37,7 +37,7 @@ export default {
isMobile() { isMobile() {
return this.$store.state.app.device === 'mobile' return this.$store.state.app.device === 'mobile'
}, },
getterFieldList() { fieldsList() {
return this.$store.getters.getFieldsListFromPanel(this.containerUuid) return this.$store.getters.getFieldsListFromPanel(this.containerUuid)
} }
}, },
@ -46,18 +46,18 @@ export default {
}, },
methods: { methods: {
getPanel() { getPanel() {
var fieldList = this.getterFieldList const fieldsList = this.fieldsList
if (fieldList && fieldList.length) { if (!this.isEmptyValue(fieldsList)) {
this.generatePanel(fieldList) this.generatePanel(fieldsList)
} }
}, },
generatePanel(fieldList) { generatePanel(fieldsList) {
this.columnListAvailable = fieldList.filter(fieldItem => { this.columnListAvailable = fieldsList.filter(fieldItem => {
return this.isDisplayed(fieldItem) return this.isDisplayed(fieldItem)
}) })
}, },
isDisplayed(field) { isDisplayed(field) {
var isDisplayed = field.isActive && field.isDisplayed && field.isDisplayedFromLogic && !field.isKey const isDisplayed = field.isActive && field.isDisplayed && field.isDisplayedFromLogic && !field.isKey
if (field.isFixedTableColumn && field.isDisplayed) { if (field.isFixedTableColumn && field.isDisplayed) {
this.columnsFixed.push(field.columnName) this.columnsFixed.push(field.columnName)
} }

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,7 @@
</el-menu-item> </el-menu-item>
<el-menu-item <el-menu-item
v-if="isPanelWindow" v-if="isPanelWindow"
:disabled="Boolean(getDataSelection.length < 1 || (isReadOnlyParent && !isParent))" :disabled="isEmptyValue(getDataSelection) || (isReadOnlyParent && !isParent)"
@click="deleteSelection()" @click="deleteSelection()"
> >
{{ $t('table.dataTable.deleteSelection') }} {{ $t('table.dataTable.deleteSelection') }}
@ -26,9 +26,9 @@
<el-menu-item <el-menu-item
v-for="(process, key) in processMenu" v-for="(process, key) in processMenu"
:key="key" :key="key"
:disabled="process.type === 'application' ? false : Boolean(getDataSelection.length < 1)" :disabled="process.type === 'application' ? false : isEmptyValue(getDataSelection)"
:index="'process' + key" :index="'process' + key"
@click="process.type === 'application' ? sortTab(process) : showModalTable(process)" @click="showModalTable(process)"
> >
{{ process.name }} {{ process.name }}
</el-menu-item> </el-menu-item>
@ -39,7 +39,7 @@
{{ $t('table.dataTable.exportZip') }} {{ $t('table.dataTable.exportZip') }}
</el-menu-item> </el-menu-item>
<el-submenu <el-submenu
:disabled="Boolean(getDataSelection.length < 1)" :disabled="isEmptyValue(getDataSelection)"
index="xlsx" index="xlsx"
@click.native="exporRecordTable(defaultFromatExport)" @click.native="exporRecordTable(defaultFromatExport)"
> >
@ -72,7 +72,7 @@
</el-menu-item> </el-menu-item>
<el-menu-item <el-menu-item
v-if="!isPanelWindow" v-if="!isPanelWindow"
:disabled="Boolean(getDataSelection.length < 1)" :disabled="isEmptyValue(getDataSelection)"
index="zoom-record" index="zoom-record"
@click="zoomRecord()" @click="zoomRecord()"
> >

View File

@ -1,42 +1,22 @@
import { supportedTypes, exportFileFromJson, exportFileZip } from '@/utils/ADempiere/exportUtil.js' import { supportedTypes, exportFileFromJson, exportFileZip } from '@/utils/ADempiere/exportUtil.js'
import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js' import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js'
import { FIELDS_QUANTITY } from '@/utils/ADempiere/references' import { FIELDS_QUANTITY } from '@/utils/ADempiere/references'
import TableMixin from '@/components/ADempiere/DataTable/mixin/tableMixin.js'
export default { export default {
name: 'MixinMenuTable', name: 'MixinMenuTable',
mixins: [
TableMixin
],
props: { props: {
parentUuid: {
type: String,
default: undefined
},
containerUuid: {
type: String,
required: true
},
panelType: {
type: String,
default: 'window'
},
currentRow: { currentRow: {
type: Object, type: Object,
default: () => {} default: () => {}
}, },
isParent: {
type: Boolean,
default: false
},
processMenu: { processMenu: {
type: Array, type: Array,
default: () => [] default: () => []
}, },
isPanelWindow: {
type: Boolean,
default: false
},
isMobile: {
type: Boolean,
default: false
},
panelMetadata: { panelMetadata: {
type: Object, type: Object,
default: () => {} default: () => {}
@ -60,73 +40,23 @@ export default {
} }
return 'menu-table' return 'menu-table'
}, },
getterDataRecordsAndSelection() {
return this.$store.getters.getDataRecordAndSelection(this.containerUuid)
},
getterNewRecords() {
if (this.isPanelWindow && !this.isParent) {
const newRecordTable = this.getterDataRecordsAndSelection.record.filter(recordItem => {
return recordItem.isNew
})
return newRecordTable.length
}
return 0
},
getDataSelection() {
return this.getterDataRecordsAndSelection.selection
},
getDataAllRecord() {
return this.getterDataRecordsAndSelection.record
},
fieldsList() { fieldsList() {
if (this.panelMetadata && this.panelMetadata.fieldList) { if (this.panelMetadata && this.panelMetadata.fieldsList) {
return this.panelMetadata.fieldList return this.panelMetadata.fieldsList
} }
return [] return []
}, },
isReadOnlyParent() {
if (this.isPanelWindow) {
if (!this.$store.getters.getContainerIsActive(this.parentUuid)) {
return true
}
if (this.$store.getters.getContainerProcessing(this.parentUuid)) {
return true
}
if (this.$store.getters.getContainerProcessed(this.parentUuid)) {
return true
}
}
return false
},
isDisabledAddNew() {
if (this.isParent) {
return true
}
if (this.$route.query.action === 'create-new') {
return true
}
if (!this.panelMetadata.isInsertRecord) {
return true
}
if (this.isReadOnlyParent) {
return true
}
if (this.getterNewRecords) {
return true
}
return false
},
isFieldsQuantity() { isFieldsQuantity() {
const fieldsQuantity = this.getterFieldList.filter(fieldItem => { const fieldsQuantity = this.getterFieldsList.filter(fieldItem => {
return FIELDS_QUANTITY.includes(fieldItem.displayType) return FIELDS_QUANTITY.includes(fieldItem.displayType)
}).length }).length
return !fieldsQuantity return !fieldsQuantity
}, },
getterFieldList() { getterFieldsList() {
return this.$store.getters.getFieldsListFromPanel(this.containerUuid) return this.$store.getters.getFieldsListFromPanel(this.containerUuid)
}, },
getterFieldListHeader() { getterFieldsListHeader() {
const header = this.getterFieldList.filter(fieldItem => { const header = this.getterFieldsList.filter(fieldItem => {
const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic
if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) { if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) {
return fieldItem.name return fieldItem.name
@ -136,8 +66,8 @@ export default {
return fieldItem.name return fieldItem.name
}) })
}, },
getterFieldListValue() { getterFieldsListValue() {
const value = this.getterFieldList.filter(fieldItem => { const value = this.getterFieldsList.filter(fieldItem => {
const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic
if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) { if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) {
return fieldItem return fieldItem
@ -163,16 +93,12 @@ export default {
parentRecordUuid: this.$route.query.action parentRecordUuid: this.$route.query.action
}) })
}, },
closeMenu() {
// TODO: Validate to dispatch one action
this.$store.dispatch('showMenuTable', {
isShowedTable: false
})
this.$store.dispatch('showMenuTabChildren', {
isShowedTabChildren: false
})
},
showModalTable(process) { showModalTable(process) {
if (process.type === 'application') {
this.sortTab(process)
return
}
const processData = this.$store.getters.getProcess(process.uuid) const processData = this.$store.getters.getProcess(process.uuid)
if (!this.currentRow) { if (!this.currentRow) {
this.$store.dispatch('setProcessSelect', { this.$store.dispatch('setProcessSelect', {
@ -231,30 +157,18 @@ export default {
containerUuid: this.containerUuid containerUuid: this.containerUuid
}) })
}, },
deleteSelection() {
this.$store.dispatch('deleteSelectionDataList', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid
}).then(() => {
this.$store.dispatch('setRecordSelection', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
panelType: this.panelType
})
})
},
addNewRow() { addNewRow() {
if (this.getterNewRecords <= 0) { if (this.newRecordsQuantity <= 0) {
this.$store.dispatch('addNewRow', { this.$store.dispatch('addNewRow', {
parentUuid: this.parentUuid, parentUuid: this.parentUuid,
containerUuid: this.containerUuid, containerUuid: this.containerUuid,
fieldList: this.fieldsList, fieldsList: this.fieldsList,
isEdit: true, isEdit: true,
isSendServer: false isSendServer: false
}) })
return return
} }
const fieldsEmpty = this.$store.getters.getFieldListEmptyMandatory({ const fieldsEmpty = this.$store.getters.getFieldsListEmptyMandatory({
containerUuid: this.containerUuid containerUuid: this.containerUuid
}) })
this.$message({ this.$message({
@ -273,11 +187,14 @@ export default {
* @param {string} formatToExport * @param {string} formatToExport
*/ */
exporRecordTable(formatToExport) { exporRecordTable(formatToExport) {
const header = this.getterFieldListHeader const header = this.getterFieldsListHeader
const filterVal = this.getterFieldListValue const filterVal = this.getterFieldsListValue
let list = this.getDataSelection
let list = []
if (this.menuType === 'tableContextMenu') { if (this.menuType === 'tableContextMenu') {
list = [this.currentRow] list = [this.currentRow]
} else {
list = this.getDataSelection
} }
const data = this.formatJson(filterVal, list) const data = this.formatJson(filterVal, list)
@ -290,11 +207,11 @@ export default {
this.closeMenu() this.closeMenu()
}, },
exporZipRecordTable() { exporZipRecordTable() {
const header = this.getterFieldListHeader const header = this.getterFieldsListHeader
const filterVal = this.getterFieldListValue const filterVal = this.getterFieldsListValue
let list = this.getDataSelection let list = this.getDataSelection
if (this.getDataSelection.length <= 0) { if (this.getDataSelection.length <= 0) {
list = this.getDataAllRecord list = this.recordsData
} }
const data = this.formatJson(filterVal, list) const data = this.formatJson(filterVal, list)
exportFileZip({ exportFileZip({
@ -313,7 +230,7 @@ export default {
}, },
zoomRecord() { zoomRecord() {
const browserMetadata = this.$store.getters.getBrowser(this.$route.meta.uuid) const browserMetadata = this.$store.getters.getBrowser(this.$route.meta.uuid)
const { elementName } = browserMetadata.fieldList.find(field => field.columnName === browserMetadata.keyColumn) const { elementName } = browserMetadata.fieldsList.find(field => field.columnName === browserMetadata.keyColumn)
const records = [] const records = []
this.getDataSelection.forEach(recordItem => { this.getDataSelection.forEach(recordItem => {
let record = recordItem[browserMetadata.keyColumn] let record = recordItem[browserMetadata.keyColumn]
@ -337,9 +254,7 @@ export default {
action: 'advancedQuery', action: 'advancedQuery',
[elementName]: records [elementName]: records
} }
}).catch(error => { }, () => {})
console.info(`Table Menu Mixin: ${error.name}, ${error.message}`)
})
} }
} }
} }

View File

@ -4,7 +4,7 @@
> >
<el-submenu <el-submenu
index="xlsx" index="xlsx"
@click.native="exportRecord(defaultFromatExport)" @click.native="exporRecordTable(defaultFromatExport)"
> >
<template slot="title"> <template slot="title">
{{ $t('data.exportRecord') }} {{ $t('data.exportRecord') }}
@ -13,7 +13,7 @@
v-for="(format, keyFormat) in supportedTypes" v-for="(format, keyFormat) in supportedTypes"
:key="keyFormat" :key="keyFormat"
:index="keyFormat" :index="keyFormat"
@click.native="exportRecord(keyFormat)" @click.native="exporRecordTable(keyFormat)"
> >
{{ format }} {{ format }}
</el-menu-item> </el-menu-item>

View File

@ -0,0 +1,40 @@
import Sortable from 'sortablejs'
export default {
name: 'MixinTableSort',
data() {
return {
sortable: null
}
},
methods: {
async getList() {
this.oldgetDataDetail = this.recordsData.map(v => v.id)
this.newgetDataDetail = this.oldgetDataDetail.slice()
this.$nextTick(() => {
this.setSort()
})
},
setSort() {
if (!this.isMobile) {
const el = this.$refs.multipleTable.$el.querySelectorAll('.el-table__body-wrapper > table > tbody')[0]
this.sortable = Sortable.create(el, {
ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
setData: dataTransfer => {
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
},
onEnd: evt => {
const targetRow = this.recordsData.splice(evt.oldIndex, 1)[0]
this.recordsData.splice(evt.newIndex, 0, targetRow)
// for show the changes, you can delete in you code
const tempIndex = this.newgetDataDetail.splice(evt.oldIndex, 1)[0]
this.newgetDataDetail.splice(evt.newIndex, 0, tempIndex)
}
})
}
}
}
}

View File

@ -0,0 +1,109 @@
export default {
name: 'TableMixin',
props: {
parentUuid: {
type: String,
default: undefined
},
containerUuid: {
type: String,
required: true
},
panelType: {
type: String,
default: 'window'
},
// is used in root view with primary records
isParent: {
type: Boolean,
default: false
}
},
computed: {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isCreateNewRoute() {
return this.$route.query.action === 'create-new'
},
isPanelWindow() {
return Boolean(this.panelType === 'window')
},
isReadOnlyParent() {
if (this.isPanelWindow) {
if (!this.$store.getters.getContainerIsActive(this.parentUuid)) {
return true
}
if (this.$store.getters.getContainerProcessing(this.parentUuid)) {
return true
}
if (this.$store.getters.getContainerProcessed(this.parentUuid)) {
return true
}
}
return false
},
isDisabledAddNew() {
if (this.isParent) {
return true
}
if (this.isCreateNewRoute) {
return true
}
const panelMetadata = this.panelMetadata
if (panelMetadata && !panelMetadata.isInsertRecord) {
return true
}
if (this.isReadOnlyParent) {
return true
}
if (this.getterNewRecords) {
return true
}
return false
},
// records, selection, record count
getterDataRecordsAndSelection() {
return this.$store.getters.getDataRecordAndSelection(this.containerUuid)
},
recordsData() {
return this.getterDataRecordsAndSelection.record
},
getDataSelection() {
return this.getterDataRecordsAndSelection.selection
},
newRecordsQuantity() {
if (this.isPanelWindow && !this.isParent) {
const newRecordTable = this.getterDataRecordsAndSelection.record.filter(recordItem => {
return recordItem.isNew
})
return newRecordTable.length
}
return 0
}
},
methods: {
closeMenu() {
// TODO: Validate to dispatch one action
this.$store.dispatch('showMenuTable', {
isShowedTable: false
})
this.$store.dispatch('showMenuTabChildren', {
isShowedTabChildren: false
})
},
deleteSelection() {
this.$store.dispatch('deleteSelectionDataList', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid
})
.then(() => {
this.$store.dispatch('setRecordSelection', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
panelType: this.panelType
})
})
}
}
}

View File

@ -140,9 +140,7 @@ export default {
...this.$route.query, ...this.$route.query,
action: this.windowRecordSelected.UUID action: this.windowRecordSelected.UUID
} }
}).catch(error => { }, () => {})
console.info(`${this.name} Component: ${error.name}, ${error.message}`)
})
this.closeDialog() this.closeDialog()
} else if (action !== undefined) { } else if (action !== undefined) {
const fieldNotReady = this.$store.getters.isNotReadyForSubmit(action.uuid) const fieldNotReady = this.$store.getters.isNotReadyForSubmit(action.uuid)

View File

@ -92,9 +92,7 @@ export default {
...this.$router.params, ...this.$router.params,
childs: item.children childs: item.children
} }
}).catch(error => { }, () => {})
console.info(`${this.name} Component: ${error.name}, ${error.message}`)
})
} }
} }
} }

View File

@ -48,9 +48,6 @@ export default {
isPanelWindow() { isPanelWindow() {
return this.metadata.panelType === 'window' return this.metadata.panelType === 'window'
}, },
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSelectMultiple() { isSelectMultiple() {
return ['IN', 'NOT_IN'].includes(this.metadata.operator) && this.metadata.isAdvancedQuery return ['IN', 'NOT_IN'].includes(this.metadata.operator) && this.metadata.isAdvancedQuery
}, },

View File

@ -123,8 +123,8 @@ export default {
*/ */
formatView() { formatView() {
let format = '' let format = ''
if (!this.isEmptyValue(this.metadata.VFormat)) { if (!this.isEmptyValue(this.metadata.vFormat)) {
format = this.metadata.VFormat format = this.metadata.vFormat
.replace(/[Y]/gi, 'y') .replace(/[Y]/gi, 'y')
.replace(/[m]/gi, 'M') .replace(/[m]/gi, 'M')
.replace(/[D]/gi, 'd') .replace(/[D]/gi, 'd')
@ -153,10 +153,22 @@ export default {
}, },
value: { value: {
get() { get() {
const { columnName, containerUuid } = this.metadata
// table records values
if (this.metadata.inTable) {
const row = this.$store.getters.getRowData({
containerUuid,
index: this.metadata.tableIndex
})
return row[columnName]
}
// main panel values
let value = this.$store.getters.getValueOfField({ let value = this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid, parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid, containerUuid,
columnName: this.metadata.columnName columnName
}) })
if (!this.metadata.isRange) { if (!this.metadata.isRange) {
return this.parseValue(value) return this.parseValue(value)
@ -164,7 +176,7 @@ export default {
const valueTo = this.$store.getters.getValueOfField({ const valueTo = this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid, parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid, containerUuid,
columnName: this.metadata.columnNameTo columnName: this.metadata.columnNameTo
}) })

View File

@ -12,6 +12,7 @@ export default [
...fieldBase, ...fieldBase,
columnName: 'C_Location_ID', columnName: 'C_Location_ID',
overwriteDefinition: { overwriteDefinition: {
isCustomField: true,
size: 24, size: 24,
isDisplayed: false, isDisplayed: false,
index: 1 index: 1
@ -21,6 +22,7 @@ export default [
...fieldBase, ...fieldBase,
columnName: 'C_Country_ID', columnName: 'C_Country_ID',
overwriteDefinition: { overwriteDefinition: {
isCustomField: true,
isActiveLogics: true, // enable logics isActiveLogics: true, // enable logics
defaultValue: '@#C_Country_ID@', defaultValue: '@#C_Country_ID@',
size: 24, size: 24,
@ -32,6 +34,7 @@ export default [
...fieldBase, ...fieldBase,
columnName: 'C_Region_ID', columnName: 'C_Region_ID',
overwriteDefinition: { overwriteDefinition: {
isCustomField: true,
size: 24, size: 24,
sequenceFields: 'R', sequenceFields: 'R',
index: 3 index: 3
@ -41,6 +44,7 @@ export default [
...fieldBase, ...fieldBase,
columnName: 'C_City_ID', columnName: 'C_City_ID',
overwriteDefinition: { overwriteDefinition: {
isCustomField: true,
size: 24, size: 24,
sequenceFields: 'C', sequenceFields: 'C',
index: 4 index: 4
@ -50,6 +54,7 @@ export default [
...fieldBase, ...fieldBase,
columnName: 'Address1', columnName: 'Address1',
overwriteDefinition: { overwriteDefinition: {
isCustomField: true,
size: 24, size: 24,
sequenceFields: 'A1', sequenceFields: 'A1',
index: 5 index: 5
@ -59,6 +64,7 @@ export default [
...fieldBase, ...fieldBase,
columnName: 'Address2', columnName: 'Address2',
overwriteDefinition: { overwriteDefinition: {
isCustomField: true,
size: 24, size: 24,
sequenceFields: 'A2', sequenceFields: 'A2',
index: 6 index: 6
@ -68,6 +74,7 @@ export default [
...fieldBase, ...fieldBase,
columnName: 'Address3', columnName: 'Address3',
overwriteDefinition: { overwriteDefinition: {
isCustomField: true,
size: 24, size: 24,
sequenceFields: 'A3', sequenceFields: 'A3',
index: 7 index: 7
@ -77,6 +84,7 @@ export default [
...fieldBase, ...fieldBase,
columnName: 'Address4', columnName: 'Address4',
overwriteDefinition: { overwriteDefinition: {
isCustomField: true,
size: 24, size: 24,
sequenceFields: 'A4', sequenceFields: 'A4',
index: 8 index: 8
@ -86,6 +94,7 @@ export default [
...fieldBase, ...fieldBase,
columnName: 'Postal', columnName: 'Postal',
overwriteDefinition: { overwriteDefinition: {
isCustomField: true,
size: 24, size: 24,
sequenceFields: 'P', sequenceFields: 'P',
index: 9 index: 9

View File

@ -138,8 +138,8 @@ export default {
if (mutation.payload.columnName === 'C_Country_ID') { if (mutation.payload.columnName === 'C_Country_ID') {
const values = [] const values = []
// Get country definition to sequence fields and displayed value // Get country definition to sequence fields and displayed value
if (mutation.value !== this.currentCountryDefinition.id) { if (mutation.value !== this.currentCountryDefinition.countryId) {
this.getCountryDefinition({ this.requestGetCountryDefinition({
id: mutation.payload.value id: mutation.payload.value
}) })
.then(responseCountry => { .then(responseCountry => {
@ -209,14 +209,35 @@ export default {
value: this.getDisplayedValue(values) value: this.getDisplayedValue(values)
}) })
// active update record to server this.$store.commit('updateValueOfField', {
this.$store.dispatch('notifyFieldChange', { parentUuid,
containerUuid, containerUuid,
field: this.parentMetadata columnName: 'Postal',
value: values.Postal
}) })
this.$store.commit('updateValueOfField', {
parentUuid,
containerUuid,
columnName: 'C_Country_ID',
value: values.C_Country_ID
})
this.$store.commit('updateValueOfField', {
parentUuid,
containerUuid,
columnName: 'C_City_ID',
value: values.C_City_ID
})
// active update record to server
// this.$store.dispatch('notifyFieldChange', {
// containerUuid,
// field: this.parentMetadata
// })
}, },
sendValuesToServer() { sendValuesToServer() {
const fieldsNotReady = this.$store.getters.getFieldListEmptyMandatory({ const fieldsNotReady = this.$store.getters.getFieldsListEmptyMandatory({
containerUuid: this.containerUuid containerUuid: this.containerUuid
}) })
if (!this.isEmptyValue(fieldsNotReady)) { if (!this.isEmptyValue(fieldsNotReady)) {
@ -247,15 +268,13 @@ export default {
}) })
const updateLocation = (responseLocation) => { const updateLocation = (responseLocation) => {
const { values } = responseLocation
// set form values // set form values
this.setValues({ this.setValues({
values values: responseLocation.attributes
}) })
// set field parent values // set field parent values
this.setParentValues(values) this.setParentValues(responseLocation.attributes)
this.setShowedLocationForm(false) this.setShowedLocationForm(false)
// set context values to parent continer // set context values to parent continer
@ -270,7 +289,7 @@ export default {
if (this.isEmptyValue(locationId) || locationId === 0) { if (this.isEmptyValue(locationId) || locationId === 0) {
requestCreateLocationAddress({ requestCreateLocationAddress({
attributes: attributesToServer attributesList: attributesToServer
}) })
.then(updateLocation) .then(updateLocation)
.catch(error => { .catch(error => {
@ -286,7 +305,7 @@ export default {
} }
requestUpdateLocationAddress({ requestUpdateLocationAddress({
id: locationId, id: locationId,
attributes: attributesToServer attributesList: attributesToServer
}) })
.then(updateLocation) .then(updateLocation)
.catch(error => { .catch(error => {

View File

@ -1,11 +1,11 @@
import { getCountryDefinition } from '@/api/ADempiere/system-core.js' import { requestGetCountryDefinition } from '@/api/ADempiere/system-core.js'
import { requestGetLocationAddress } from '@/api/ADempiere/field/location.js' import { requestGetLocationAddress } from '@/api/ADempiere/field/location.js'
export default { export default {
name: 'MixinLocationField', name: 'MixinLocationField',
computed: { computed: {
currentCountryDefinition() { currentCountryDefinition() {
return this.$store.getters['user/getCountry'] return this.$store.getters.getCountry
}, },
isShowedLocationForm: { isShowedLocationForm: {
get() { get() {
@ -18,7 +18,7 @@ export default {
}, },
methods: { methods: {
requestGetLocationAddress, requestGetLocationAddress,
getCountryDefinition, requestGetCountryDefinition,
toggleShowedLocationForm() { toggleShowedLocationForm() {
this.$store.commit('setShowedLocation', !this.isShowedLocationForm) this.$store.commit('setShowedLocation', !this.isShowedLocationForm)
}, },

View File

@ -18,11 +18,13 @@
<script> <script>
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js' import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import { getLocatorList } from '@/api/ADempiere/field/locator' import { requestLocatorList } from '@/api/ADempiere/field/locator.js'
export default { export default {
name: 'FieldLocation', name: 'FieldLocation',
mixins: [fieldMixin], mixins: [
fieldMixin
],
data() { data() {
return { return {
options: [], options: [],
@ -58,16 +60,18 @@ export default {
if (Array.isArray(value)) { if (Array.isArray(value)) {
selected = value[value.length - 1] selected = value[value.length - 1]
} }
this.handleFieldChange({ value: selected }) this.handleFieldChange({
value: selected
})
this.value = value this.value = value
}, },
searchLocatorByWarehouse(node, resolve) { searchLocatorByWarehouse(node, resolve) {
getLocatorList({ requestLocatorList({
warehouseId: node.value warehouseId: node.value
}) })
.then(responseData => { .then(responseData => {
const locatorList = responseData.recordsList.map(item => { const locatorList = responseData.recordsList.map(item => {
const { values } = item const { attributes: values } = item
return { return {
label: values.Value, label: values.Value,
value: values.M_Locator_ID, value: values.M_Locator_ID,

View File

@ -82,7 +82,7 @@ export default {
precision() { precision() {
// Amount, Costs+Prices, Number // Amount, Costs+Prices, Number
if (this.isDecimal) { if (this.isDecimal) {
return this.currencyDefinition.stdPrecision return this.currencyDefinition.standardPrecision
} }
return undefined return undefined
}, },
@ -140,13 +140,13 @@ export default {
return formatterInstance.format(value) return formatterInstance.format(value)
}, },
countryLanguage() { countryLanguage() {
return this.$store.getters['user/getCountryLanguage'] return this.$store.getters.getCountryLanguage
}, },
currencyCode() { currencyCode() {
return this.currencyDefinition.iSOCode return this.currencyDefinition.iSOCode
}, },
currencyDefinition() { currencyDefinition() {
return this.$store.getters['user/getCurrency'] return this.$store.getters.getCurrency
} }
}, },
methods: { methods: {

View File

@ -62,9 +62,6 @@ export default {
isPanelWindow() { isPanelWindow() {
return this.metadata.panelType === 'window' return this.metadata.panelType === 'window'
}, },
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isSelectMultiple() { isSelectMultiple() {
return ['IN', 'NOT_IN'].includes(this.metadata.operator) && this.metadata.isAdvancedQuery return ['IN', 'NOT_IN'].includes(this.metadata.operator) && this.metadata.isAdvancedQuery
}, },
@ -110,11 +107,23 @@ export default {
}, },
value: { value: {
get() { get() {
const value = this.$store.getters.getValueOfField({ const { columnName, containerUuid } = this.metadata
parentUuid: this.metadata.parentUuid, let value
containerUuid: this.metadata.containerUuid, // table records values
columnName: this.metadata.columnName if (this.metadata.inTable) {
const row = this.$store.getters.getRowData({
containerUuid,
index: this.metadata.tableIndex
}) })
value = row[columnName]
} else {
value = this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid,
containerUuid,
columnName
})
}
if (this.isEmptyValue(value)) { if (this.isEmptyValue(value)) {
/* eslint-disable */ /* eslint-disable */
this.displayedValue = undefined this.displayedValue = undefined
@ -152,6 +161,9 @@ export default {
}, },
uuidValue: { uuidValue: {
get() { get() {
if (this.metadata.inTable) {
return undefined
}
return this.$store.getters.getValueOfField({ return this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid, parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid, containerUuid: this.metadata.containerUuid,
@ -160,6 +172,9 @@ export default {
}) })
}, },
set(value) { set(value) {
if (this.metadata.inTable) {
return undefined
}
this.$store.commit('updateValueOfField', { this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid, parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid, containerUuid: this.metadata.containerUuid,
@ -171,11 +186,21 @@ export default {
}, },
displayedValue: { displayedValue: {
get() { get() {
const { displayColumnName: columnName, containerUuid } = this.metadata
// table records values
if (this.metadata.inTable) {
const row = this.$store.getters.getRowData({
containerUuid,
index: this.metadata.tableIndex
})
// DisplayColumn_'ColumnName'
return row[columnName]
}
return this.$store.getters.getValueOfField({ return this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid, parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid, containerUuid,
// DisplayColumn_'ColumnName' // DisplayColumn_'ColumnName'
columnName: this.metadata.displayColumnName columnName
}) })
}, },
set(value) { set(value) {
@ -240,8 +265,8 @@ export default {
}) })
} else { } else {
if (!this.isPanelWindow || (this.isPanelWindow && if (!this.isPanelWindow || (this.isPanelWindow &&
(this.isEmptyValue(this.metadata.optionCRUD) || !this.isEmptyValue(this.$route.query) &&
this.metadata.optionCRUD === 'create-new'))) { this.$route.query.action === 'create-new')) {
this.getDataLookupItem() this.getDataLookupItem()
} }
} }
@ -259,11 +284,11 @@ export default {
}, },
changeBlankOption() { changeBlankOption() {
if (Number(this.metadata.defaultValue) === -1) { if (Number(this.metadata.defaultValue) === -1) {
this.blankOption.id = -1 this.blankOption.id = this.metadata.defaultValue
} }
}, },
preHandleChange(value) { preHandleChange(value) {
const label = this.findLabel(this.value) const { label } = this.findOption(value)
this.displayedValue = label this.displayedValue = label
this.handleFieldChange({ this.handleFieldChange({
value, value,
@ -281,17 +306,6 @@ export default {
uuid: undefined uuid: undefined
} }
}, },
/**
* TODO: Verify used
* @deprecated use findOption
*/
findLabel(value) {
const selected = this.optionsList.find(item => item.id === value)
if (selected) {
return selected.label
}
return selected
},
async getDataLookupItem() { async getDataLookupItem() {
if (this.isEmptyValue(this.metadata.reference.directQuery) || if (this.isEmptyValue(this.metadata.reference.directQuery) ||
(this.metadata.isAdvancedQuery && this.isSelectMultiple)) { (this.metadata.isAdvancedQuery && this.isSelectMultiple)) {
@ -301,6 +315,7 @@ export default {
this.$store.dispatch('getLookupItemFromServer', { this.$store.dispatch('getLookupItemFromServer', {
parentUuid: this.metadata.parentUuid, parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid, containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName,
tableName: this.metadata.reference.tableName, tableName: this.metadata.reference.tableName,
directQuery: this.metadata.reference.directQuery, directQuery: this.metadata.reference.directQuery,
value: this.value value: this.value
@ -308,8 +323,10 @@ export default {
.then(responseLookupItem => { .then(responseLookupItem => {
this.displayedValue = responseLookupItem.label this.displayedValue = responseLookupItem.label
this.uuidValue = responseLookupItem.uuid this.uuidValue = responseLookupItem.uuid
this.$nextTick(() => {
this.optionsList = this.getterLookupAll this.optionsList = this.getterLookupAll
}) })
})
.finally(() => { .finally(() => {
this.isLoading = false this.isLoading = false
}) })
@ -331,8 +348,10 @@ export default {
this.$store.dispatch('getLookupListFromServer', { this.$store.dispatch('getLookupListFromServer', {
parentUuid: this.metadata.parentUuid, parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid, containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName,
tableName: this.metadata.reference.tableName, tableName: this.metadata.reference.tableName,
query: this.metadata.reference.query, query: this.metadata.reference.query,
whereClause: this.metadata.validationCode,
// valuesList: this.value // valuesList: this.value
isAddBlankValue: true, isAddBlankValue: true,
blankValue: this.blankOption.id blankValue: this.blankOption.id

View File

@ -24,6 +24,8 @@ import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
*/ */
export default { export default {
name: 'FieldSelectMultiple', name: 'FieldSelectMultiple',
mixins: [fieldMixin] mixins: [
fieldMixin
]
} }
</script> </script>

View File

@ -1,164 +0,0 @@
<template>
<div :id="id" :class="classDisable" />
</template>
<script>
// deps for editor
import 'tui-editor/dist/tui-editor.css' // editor ui
import 'tui-editor/dist/tui-editor-contents.css' // editor content
import 'codemirror/lib/codemirror.css' // codemirror
import Editor from 'tui-editor'
import { getLanguage } from '@/lang'
export default {
name: 'ChatTextLong',
props: {
id: {
type: String,
required: false,
default() {
return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0))
}
}
},
data() {
return {
mode: 'markdown', // 'markdown' or 'wysiwyg'
height: '200px',
editor: null
}
},
computed: {
classDisable() {
if (this.isDisabled) {
return 'isdisable'
}
return ''
},
clean() {
return this.$store.getters.getMarkDown
},
language() {
// https://github.com/nhnent/tui.editor/tree/master/src/js/langs
if (this.isEmptyValue(getLanguage())) {
return 'en_US'
}
return getLanguage()
},
editorOptions() {
const options = {
previewStyle: 'vertical',
useCommandShortcut: true,
usageStatistics: false, // send hostname to google analytics
hideModeSwitch: this.isDisabled
}
options.initialEditType = this.mode
options.height = this.height
options.language = this.language
return options
}
},
watch: {
clean(value) {
if (value) {
this.editor.setValue('')
}
},
value(newValue, oldValue) {
if (this.isDisabled) {
// not changed value
this.value = oldValue
this.editor.setValue(oldValue)
} else {
this.editor.setValue(newValue)
}
},
language(langValue) {
this.destroyEditor()
this.initEditor()
},
height(heightValue) {
this.editor.height(heightValue)
},
isDisabled(value) {
this.classDisable
this.destroyEditor()
this.initEditor()
}
},
mounted() {
this.initEditor()
},
destroyed() {
this.destroyEditor()
},
methods: {
initEditor() {
this.editor = new Editor({
el: document.getElementById(this.id),
...this.editorOptions
})
if (!this.isEmptyValue(this.value)) {
this.editor.setValue(this.value)
}
this.setEvents()
},
setEvents() {
if (this.isDisabled) {
this.removeEventSendValues()
this.addReanOnlyChanges()
} else {
this.addEventSendValues()
this.removeReadOnlyChanges()
}
},
addEventSendValues() {
this.editor.on('blur', () => {
this.preHandleChange(this.editor.getValue())
})
},
preHandleChange(value) {
if (this.isEmptyValue(value)) {
this.$store.dispatch('setchatText', value)
.then(responseComment => {
this.$store.dispatch('setMarkDown', false)
this.$store.dispatch('setchatText', '')
})
} else {
this.$store.dispatch('setchatText', value)
}
},
addReanOnlyChanges() {
this.editor.on('change', () => {
this.editor.setValue(this.value)
})
},
removeEventSendValues() {
this.editor.off('blur')
},
removeReadOnlyChanges() {
this.editor.off('change')
},
destroyEditor() {
if (!this.editor) {
return
}
this.removeEventSendValues()
this.removeReadOnlyChanges()
this.editor.remove()
},
setHtml(value) {
this.editor.setHtml(value)
},
getHtml() {
return this.editor.getHtml()
}
}
}
</script>
<style>
.isdisable {
background: #F5F7FA;
}
</style>

View File

@ -3,9 +3,9 @@
this v-show is to indicate that if the field is not shown, this v-show is to indicate that if the field is not shown,
therefore you should not leave the column size spacing of your therefore you should not leave the column size spacing of your
<el-col></el-col> container--> <el-col></el-col> container-->
<div v-if="!inTable">
<el-col <el-col
v-if="!inTable" v-if="isDisplayed"
v-show="isDisplayed"
key="is-panel-template" key="is-panel-template"
:xs="sizeFieldResponsive.xs" :xs="sizeFieldResponsive.xs"
:sm="sizeFieldResponsive.sm" :sm="sizeFieldResponsive.sm"
@ -60,6 +60,7 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
</div>
<component <component
:is="componentRender" :is="componentRender"
v-else v-else
@ -352,7 +353,7 @@ export default {
return false return false
} }
return Boolean(this.field.contextInfo && this.field.contextInfo.isActive) || return Boolean(this.field.contextInfo && this.field.contextInfo.isActive) ||
Boolean(this.field.reference && this.field.reference.windowsList.length) Boolean(this.field.reference && this.field.reference.zoomWindows.length)
} }
}, },
watch: { watch: {

View File

@ -11,19 +11,10 @@ export default {
default: null default: null
} }
}, },
data() {
// value render
let value1 = this.metadata.value
if (this.metadata.inTable) {
value1 = this.valueModel
}
value1 = this.parseValue(value1)
return {
value1
}
},
computed: { computed: {
isMobile() {
return this.$store.state.app.device === 'mobile'
},
isDisabled() { isDisabled() {
return Boolean(this.metadata.readonly || this.metadata.disabled) return Boolean(this.metadata.readonly || this.metadata.disabled)
}, },
@ -36,13 +27,34 @@ export default {
}, },
value: { value: {
get() { get() {
const { columnName, containerUuid } = this.metadata
// table records values
if (this.metadata.inTable) {
const row = this.$store.getters.getRowData({
containerUuid,
index: this.metadata.tableIndex
})
return row[columnName]
}
// main panel values
return this.$store.getters.getValueOfField({ return this.$store.getters.getValueOfField({
parentUuid: this.metadata.parentUuid, parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid, containerUuid,
columnName: this.metadata.columnName columnName
}) })
}, },
set(value) { set(value) {
if (this.metadata.inTable) {
this.$store.dispatch('notifyCellTableChange', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
newValue: value,
field: this.metadata
})
return
}
this.$store.commit('updateValueOfField', { this.$store.commit('updateValueOfField', {
parentUuid: this.metadata.parentUuid, parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid, containerUuid: this.metadata.containerUuid,
@ -177,6 +189,14 @@ export default {
} }
return return
} }
if (this.metadata.inTable) {
this.$store.dispatch('notifyCellTableChange', {
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
field: this.metadata
})
}
this.$store.dispatch('notifyFieldChange', { this.$store.dispatch('notifyFieldChange', {
containerUuid: this.metadata.containerUuid, containerUuid: this.metadata.containerUuid,
field: this.metadata field: this.metadata

View File

@ -16,7 +16,7 @@
</span> </span>
{{ fieldAttributes.help }} {{ fieldAttributes.help }}
</div> </div>
<template v-for="(zoomItem, index) in fieldAttributes.reference.windowsList"> <template v-for="(zoomItem, index) in fieldAttributes.reference.zoomWindows">
<el-button <el-button
:key="index" :key="index"
type="text" type="text"
@ -81,9 +81,7 @@ export default {
tabParent: 0, tabParent: 0,
[this.fieldAttributes.columnName]: this.value [this.fieldAttributes.columnName]: this.value
} }
}).catch(error => { }, () => {})
console.info(`${this.name} Component: ${error.name}, ${error.message}`)
})
} else { } else {
this.$message({ this.$message({
type: 'error', type: 'error',

View File

@ -55,7 +55,6 @@ export default {
this.$store.dispatch('changeFieldAttribure', { this.$store.dispatch('changeFieldAttribure', {
containerUuid: this.fieldAttributes.containerUuid, containerUuid: this.fieldAttributes.containerUuid,
columnName: this.fieldAttributes.columnName, columnName: this.fieldAttributes.columnName,
isAdvancedQuery: true,
attributeName: 'operator', attributeName: 'operator',
attributeValue: operatorValue attributeValue: operatorValue
}) })

View File

@ -84,7 +84,7 @@ export default {
}, },
computed: { computed: {
languageList() { languageList() {
return this.$store.getters['user/getLanguagesList'].filter(itemLanguage => { return this.$store.getters.getLanguagesList.filter(itemLanguage => {
return !itemLanguage.isBaseLanguage return !itemLanguage.isBaseLanguage
}) })
}, },

View File

@ -4,7 +4,7 @@ export default [
elementColumnName: 'ProductValue', elementColumnName: 'ProductValue',
isFromDictionary: true, isFromDictionary: true,
overwriteDefinition: { overwriteDefinition: {
size: 12, size: 24,
sequence: 10, sequence: 10,
cssClassName: 'price-inquiry', cssClassName: 'price-inquiry',
inputSize: 'large', inputSize: 'large',

View File

@ -7,13 +7,13 @@
<el-container style="height: 100% !important;"> <el-container style="height: 100% !important;">
<img <img
fit="contain" fit="contain"
:src="valuesImage.length > 1 ? valuesImage.value : getDefaultImage()" :src="backgroundForm"
class="background-price-checking" class="background-price-checking"
> >
<el-main> <el-main>
<div class="inquiry-form">
<el-form <el-form
key="form-loaded" key="form-loaded"
class="inquiry-form"
label-position="top" label-position="top"
label-width="10px" label-width="10px"
@submit.native.prevent="notSubmitForm" @submit.native.prevent="notSubmitForm"
@ -27,7 +27,7 @@
class="product-value" class="product-value"
/> />
</el-form> </el-form>
</div>
<div class="inquiry-product"> <div class="inquiry-product">
<el-row v-if="!isEmptyValue(productPrice)" :gutter="20"> <el-row v-if="!isEmptyValue(productPrice)" :gutter="20">
<el-col style="padding-left: 0px; padding-right: 0%;"> <el-col style="padding-left: 0px; padding-right: 0%;">
@ -70,102 +70,79 @@
element-loading-background="rgba(255, 255, 255, 0.8)" element-loading-background="rgba(255, 255, 255, 0.8)"
class="loading-panel" class="loading-panel"
/> />
<!-- </div> -->
</template> </template>
<script> <script>
import formMixin from '@/components/ADempiere/Form/formMixin.js' import formMixin from '@/components/ADempiere/Form/formMixin.js'
import fieldsList from './fieldsList.js' import fieldsList from './fieldsList.js'
import { getProductPrice } from '@/api/ADempiere/form/price-checking.js' import { requestGetProductPrice } from '@/api/ADempiere/form/price-checking.js'
import { formatPercent, formatPrice } from '@/utils/ADempiere/valueFormat.js' import { formatPercent, formatPrice } from '@/utils/ADempiere/valueFormat.js'
import { getResource } from '@/api/ADempiere/persistence.js' import { buildImageFromArrayBuffer } from '@/utils/ADempiere/resource.js'
import { mergeByteArray, buildImageFromArray } from '@/utils/ADempiere/resource.js' import { requestImage } from '@/api/ADempiere/persistence.js'
export default { export default {
name: 'PriceChecking', name: 'PriceChecking',
mixins: [formMixin], mixins: [
formMixin
],
data() { data() {
return { return {
fieldsList, fieldsList,
productPrice: {}, productPrice: {},
resource: {}, organizationBackground: '',
valuesImage: [{ currentImageOfProduct: '',
identifier: 'undefined',
value: 'price-checking-background',
isLoaded: true
}],
unsubscribe: () => {} unsubscribe: () => {}
} }
}, },
computed: {
organizationImagePath() {
return this.$store.getters.avatar
},
defaultImage() {
return require('@/image/ADempiere/priceChecking/no-image.jpg')
},
backgroundForm() {
if (this.isEmptyValue(this.currentImageOfProduct)) {
return this.organizationBackground
}
return this.currentImageOfProduct
}
},
created() { created() {
this.unsubscribe = this.subscribeChanges() this.unsubscribe = this.subscribeChanges()
}, },
mounted() {
this.getImage()
},
beforeDestroy() { beforeDestroy() {
this.unsubscribe() this.unsubscribe()
}, },
methods: { methods: {
buildImageFromArray, async getImage(imageName = '') {
getDefaultImage() { let isSetOrg = false
return require('@/image/ADempiere/priceChecking/price-checking-background.png') if (this.isEmptyValue(imageName)) {
}, if (!this.isEmptyValue(this.organizationBackground)) {
getImage(resource) { return this.organizationBackground
let isImage }
if (resource) { isSetOrg = true
if (resource.image) { imageName = this.organizationImagePath
if (!this.valuesImage.some(item => item.identifier === resource.image)) { }
this.valuesImage.push({ const imageBuffer = await requestImage({
identifier: resource.image, file: imageName
value: '', }).then(responseImage => {
isLoaded: false const arrayBufferAsImage = buildImageFromArrayBuffer({
arrayBuffer: responseImage
}) })
}
if (this.resource[resource.image]) {
this.valuesImage.map(item => {
if (item.identifier === resource.image) {
return {
...item,
value: this.buildImageFromArray(resource, this.resource[resource.image]),
isLoaded: true
}
}
return item
})
} else { // Reload
if (!this.valuesImage.some(item => item.identifier === resource.image)) {
this.valuesImage.push({
identifier: resource.image,
value: '',
isLoaded: false
})
}
let result = new Uint8Array()
const callBack = {}
callBack.onData = (response) => {
result = mergeByteArray(result, response.getData())
}
callBack.onStatus = (status) => {
if (isSetOrg) {
this.organizationBackground = arrayBufferAsImage
return arrayBufferAsImage
} }
callBack.onEnd = (end) => {
this.resource[resource.image] = result this.currentImageOfProduct = arrayBufferAsImage
this.valuesImage.map(item => { return arrayBufferAsImage
if (item.identifier === resource.image) {
return {
...item,
value: this.buildImageFromArray(resource, this.resource[isImage]),
isLoaded: true
}
}
return item
}) })
} return imageBuffer
getResource({
resourceUuid: '1816f354-a868-4f4f-9a83-b0eb98cf1d05'
},
callBack)
}
}
}
}, },
focusProductValue() { focusProductValue() {
this.$refs.ProductValue[0].$children[0].$children[0].$children[1].$children[0].focus() this.$refs.ProductValue[0].$children[0].$children[0].$children[1].$children[0].focus()
@ -176,22 +153,23 @@ export default {
return this.$store.subscribe((mutation, state) => { return this.$store.subscribe((mutation, state) => {
if (mutation.type === 'addActionKeyPerformed' && mutation.payload.columnName === 'ProductValue') { if (mutation.type === 'addActionKeyPerformed' && mutation.payload.columnName === 'ProductValue') {
// cleans all values except column name 'ProductValue' // cleans all values except column name 'ProductValue'
getProductPrice({ requestGetProductPrice({
searchValue: mutation.payload.value searchValue: mutation.payload.value
}) })
.then(productPrice => { .then(productPrice => {
const { product, taxRate, priceStd: priceBase } = productPrice const { product, taxRate, priceStandard: priceBase } = productPrice
const { rate } = taxRate const { rate } = taxRate
const { imageURL: image } = product
this.productPrice = { this.productPrice = {
productName: product.name, productName: product.name,
productDescription: product.description, productDescription: product.description,
priceBase, priceBase,
priceStd: productPrice.priceStd, priceStandard: productPrice.priceStandard,
priceList: productPrice.priceList, priceList: productPrice.priceList,
priceLimit: productPrice.priceLimit, priceLimit: productPrice.priceLimit,
taxRate: rate, taxRate: rate,
image: product.imageURL, image,
taxName: taxRate.name, taxName: taxRate.name,
taxIndicator: taxRate.taxIndicator, taxIndicator: taxRate.taxIndicator,
taxAmt: this.getTaxAmount(priceBase, rate), taxAmt: this.getTaxAmount(priceBase, rate),
@ -202,7 +180,8 @@ export default {
.catch(error => { .catch(error => {
this.$message({ this.$message({
type: 'info', type: 'info',
message: error.message message: error.message,
showClose: true
}) })
this.productPrice = {} this.productPrice = {}
}) })
@ -212,7 +191,11 @@ export default {
columnName: 'ProductValue', columnName: 'ProductValue',
value: '' value: ''
}) })
this.getImage(this.productPrice)
this.currentImageOfProduct = ''
if (this.isEmptyValue(this.productPrice.image)) {
this.getImage(this.productPrice.image)
}
}) })
} }
}) })

View File

@ -0,0 +1,190 @@
<template>
<el-main
v-shortkey="shortsKey"
@shortkey.native="keyAction"
>
<el-form
label-position="top"
size="small"
class="create-bp"
>
<el-row :gutter="24">
<field-definition
v-for="(field) in fieldsList"
:key="field.columnName"
:metadata-field="field"
/>
<el-col :span="24">
<samp style="float: right; padding-right: 10px;">
<el-button
type="primary"
class="custom-button-create-bp"
icon="el-icon-check"
:loading="isLoadingRecord"
@click="createBusinessParter"
/>
<el-button
type="danger"
class="custom-button-create-bp"
icon="el-icon-close"
@click="clearValues"
/>
</samp>
</el-col>
</el-row>
</el-form>
</el-main>
</template>
<script>
import { requestCreateBusinessPartner } from '@/api/ADempiere/system-core.js'
import formMixin from '@/components/ADempiere/Form/formMixin.js'
import fieldsList from './fieldsListCreate.js'
import BParterMixin from './mixinBusinessPartner.js'
export default {
name: 'BusinessPartnerCreate',
mixins: [
formMixin,
BParterMixin
],
props: {
metadata: {
type: Object,
default: () => {
return {
uuid: 'Business-Partner-Create',
containerUuid: 'Business-Partner-Create',
fieldsList
}
}
}
},
data() {
return {
businessPartnerRecord: {},
isLoadingRecord: false,
fieldsList,
isCustomForm: true,
unsubscribe: () => {}
}
},
beforeDestroy() {
this.unsubscribe()
},
methods: {
// TODO: Get locations values.
createBusinessParter() {
let values = this.$store.getters.getValuesView({
containerUuid: this.containerUuid,
format: 'object'
})
if (this.isEmptyValue(values)) {
return
}
values = this.convertValuesToSend(values)
this.isLoadingRecord = true
requestCreateBusinessPartner(values)
.then(responseBPartner => {
// TODO: Add new record into vuex store.
this.setBusinessPartner(responseBPartner)
this.clearValues()
this.$message({
type: 'success',
message: 'Socio de negocio creado exitosamente',
duration: 1500,
showClose: true
})
})
.catch(error => {
this.showsPopovers.isShowCreate = true
this.$message({
type: 'warning',
message: error.message,
duration: 1500,
showClose: true
})
console.warn(`Error create Business Partner. Message: ${error.message}, code ${error.code}.`)
})
.finally(() => {
this.isLoadingRecord = false
})
},
clearValues() {
this.showsPopovers.isShowCreate = false
this.$store.dispatch('setDefaultValues', {
containerUuid: this.containerUuid,
panelType: this.panelType
})
this.clearLocationValues()
},
clearLocationValues() {
this.$store.commit('updateValuesOfContainer', {
containerUuid: this.containerUuid,
attributes: [{
columnName: 'C_Location_ID',
value: undefined
}, {
columnName: 'DisplayColumn_C_Location_ID',
value: undefined
}, {
columnName: 'C_Country_ID',
value: undefined
}, {
columnName: 'C_Country_ID_UUID',
value: undefined
}, {
columnName: 'DisplayColumn_C_Country_ID',
value: undefined
}, {
columnName: 'C_Region_ID',
value: undefined
}, {
columnName: 'C_Region_ID_UUID',
value: undefined
}, {
columnName: 'DisplayColumn_C_Region_ID',
value: undefined
}, {
columnName: 'C_City_ID',
value: undefined
}, {
columnName: 'C_City_ID_UUID',
value: undefined
}, {
columnName: 'DisplayColumn_C_City_ID',
value: undefined
}, {
columnName: 'Address1',
value: undefined
}, {
columnName: 'Address2',
value: undefined
}, {
columnName: 'Address3',
value: undefined
}, {
columnName: 'Address4',
value: undefined
}]
})
}
}
}
</script>
<style scoped lang="scss">
.create-bp {
.el-form-item {
margin-bottom: 0px !important;
}
}
.custom-button-create-bp {
float: right;
margin-right: 10px;
}
</style>

View File

@ -0,0 +1,206 @@
<template>
<el-main
v-shortkey="shortsKey"
@shortkey.native="keyAction"
>
<el-collapse v-model="activeAccordion" accordion>
<el-collapse-item name="query-criteria">
<template slot="title">
Business Partner
<template v-if="!isEmptyValue(parentMetadata.name)">
({{ parentMetadata.name }})
</template>
<!-- <i class="el-icon-circle-plus" /> -->
</template>
<el-form
label-position="top"
size="small"
>
<el-row>
<field-definition
v-for="(field) in fieldsList"
:key="field.columnName"
:metadata-field="field"
/>
</el-row>
</el-form>
</el-collapse-item>
</el-collapse>
<el-table
ref="businesPartnerTable"
:data="businessPartnersList"
highlight-current-row
border
fit
height="350"
@current-change="handleCurrentChange"
>
<el-table-column
label="Key"
prop="value"
width="180"
/>
<el-table-column
label="ID"
prop="id"
width="100"
/>
<el-table-column
prop="name"
label="Name"
/>
<el-table-column
label="Last Name"
prop="lastName"
/>
<el-table-column
label="NAICS"
prop="naics"
width="100"
/>
<el-table-column
label="Tax ID"
prop="taxId"
align="right"
width="100"
/>
</el-table>
<custom-pagination
:total="businessParners.recordCount"
:current-page="1"
:handle-change-page="handleChangePage"
/>
<!-- -->
</el-main>
</template>
<script>
import CustomPagination from '@/components/ADempiere/Pagination'
import formMixin from '@/components/ADempiere/Form/formMixin.js'
import fieldsList from './fieldsListSearch.js'
import BParterMixin from './mixinBusinessPartner.js'
export default {
name: 'BusinessPartnersList',
components: {
CustomPagination
},
mixins: [
formMixin,
BParterMixin
],
props: {
metadata: {
type: Object,
default: () => {
return {
uuid: 'Business-Partner-List',
containerUuid: 'Business-Partner-List'
}
}
},
showsPopovers: {
type: Object,
default: () => {
return {
isShowCreate: false,
isShowList: false
}
}
}
},
data() {
return {
isLoadedRecords: false,
activeAccordion: 'query-criteria',
fieldsList,
unsubscribe: () => {}
}
},
computed: {
businessParners() {
return this.$store.getters.getBusinessPartner
},
businessPartnersList() {
return this.$store.getters.getBusinessPartnersList
},
isReadyFromGetData() {
const { isLoaded, isReload } = this.businessParners
return (!isLoaded || isReload) && this.showsPopovers.isShowList
}
},
watch: {
isReadyFromGetData(isToLoad) {
if (isToLoad) {
this.searchBPartnerList({})
}
}
},
created() {
this.unsubscribe = this.subscribeChanges()
if (this.isReadyFromGetData) {
this.searchBPartnerList({})
}
},
beforeDestroy() {
this.unsubscribe()
},
methods: {
keyAction(event) {
switch (event.srcKey) {
case 'refreshList': {
const values = this.$store.getters.getValuesView({
containerUuid: this.metadata.containerUuid,
format: 'object'
})
this.searchBPartnerList(values)
break
}
case 'refreshListWithoutValues': {
this.searchBPartnerList({})
break
}
case 'closeForm':
this.closeForm()
break
}
},
handleCurrentChange(row) {
this.setBusinessPartner(row)
},
handleChangePage(newPage) {
this.$store.dispatch('setBPartnerPageNumber', newPage)
},
subscribeChanges() {
return this.$store.subscribe((mutation, state) => {
if (mutation.type === 'updateValueOfField' &&
mutation.payload.containerUuid === this.metadata.containerUuid) {
const values = this.$store.getters.getValuesView({
containerUuid: mutation.payload.containerUuid,
format: 'object'
})
this.searchBPartnerList(values)
}
})
},
searchBPartnerList(values, isConvert = true) {
if (isConvert && !this.isEmptyValue(values)) {
values = this.convertValuesToSend(values)
}
return this.$store.dispatch('listBPartnerFromServer', values)
.then(response => {
return response
})
.finally(() => {
this.isLoadedRecords = true
})
}
}
}
</script>

View File

@ -0,0 +1,68 @@
// List of fields to send for create new
export default [
{
columnName: 'Value',
// displayType: CHAR.id,
definition: {
name: 'Search Key',
isCustomField: true,
size: 24
}
},
{
columnName: 'Name',
// displayType: CHAR.id,
definition: {
name: 'Name',
isCustomField: true,
size: 24
}
},
{
columnName: 'Contact',
// displayType: CHAR.id,
definition: {
name: 'Contact Name',
isCustomField: true,
size: 24
}
},
{
columnName: 'EMail',
// displayType: CHAR.id,
definition: {
name: 'E-Mail Address',
isCustomField: true,
size: 24
}
},
{
columnName: 'Postal',
// displayType: CHAR.id,
definition: {
name: 'Postal Code',
isCustomField: true,
size: 24
}
},
{
columnName: 'Phone',
// displayType: CHAR.id,
definition: {
name: 'Phone',
isCustomField: true,
size: 24
}
},
{
columnName: 'C_Location_ID',
tableName: 'C_BPartner_Location',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
handleActionPerformed: false,
isSendParentValues: true,
popoverPlacement: 'top'
}
}
]

View File

@ -0,0 +1,59 @@
// List of fields to send in search
export default [
{
columnName: 'Code',
// displayType: CHAR.id,
definition: {
name: 'Search Value',
isCustomField: true
}
},
{
columnName: 'Value',
// displayType: CHAR.id,
definition: {
name: 'Search Key',
isCustomField: true
}
},
{
columnName: 'Name',
// displayType: CHAR.id,
definition: {
name: 'Name',
isCustomField: true
}
},
{
columnName: 'Contact',
// displayType: CHAR.id,
definition: {
name: 'Contact Name',
isCustomField: true
}
},
{
columnName: 'EMail',
// displayType: CHAR.id,
definition: {
name: 'E-Mail Address',
isCustomField: true
}
},
{
columnName: 'Postal',
// displayType: CHAR.id,
definition: {
name: 'Postal Code',
isCustomField: true
}
},
{
columnName: 'Phone',
// displayType: CHAR.id,
definition: {
name: 'Phone',
isCustomField: true
}
}
]

View File

@ -0,0 +1,386 @@
<template>
<div>
<el-popover
ref="businessPartnerCreate"
v-model="showsPopovers.isShowCreate"
placement="right"
width="400"
trigger="click"
>
<business-partner-create
v-if="showsPopovers.isShowCreate"
:parent-metadata="parentMetadata"
:shows-popovers="showsPopovers"
/>
</el-popover>
<el-popover
ref="businessPartnersList"
v-model="showsPopovers.isShowList"
placement="right"
width="800"
trigger="click"
>
<!-- v-if="showsPopovers.isShowList" -->
<business-partners-list
:parent-metadata="parentMetadata"
:shows-popovers="showsPopovers"
/>
</el-popover>
<el-form-item>
<template slot="label">
Business Partner
<i
v-popover:businessPartnerCreate
class="el-icon-circle-plus"
/>
<i
v-popover:businessPartnersList
class="el-icon-search"
/>
</template>
<el-autocomplete
v-model="displayedValue"
:placeholder="$t('quickAccess.searchWithEnter')"
:fetch-suggestions="localSearch"
clearable
value-key="name"
style="width: 100%;"
popper-class="custom-field-bpartner-info"
@clear="setBusinessPartner(blankBPartner, false)"
@keyup.enter.native="getBPartnerWithEnter"
@select="handleSelect"
@focus="setNewDisplayedValue"
@blur="setOldDisplayedValue"
>
<template
slot="prefix"
>
<i
class="el-icon-user-solid el-input__icon"
/>
</template>
<template slot-scope="props">
<div class="header">
<b>{{ props.item.name }} </b>
</div>
<span class="info">
{{ props.item.value }}
</span>
</template>
</el-autocomplete>
</el-form-item>
</div>
</template>
<script>
/**
* This component is made to be the prototype of the Business Partner search field
* TODO: Before creating you must make a search for all the filled fields.
*/
import { requestGetBusinessPartner } from '@/api/ADempiere/system-core.js'
import BusinessPartnerCreate from './businessPartnerCreate'
import BusinessPartnersList from './businessPartnersList'
import BParterMixin from './mixinBusinessPartner.js'
const { setBusinessPartner } = BParterMixin.methods
const { searchBPartnerList } = BusinessPartnersList.methods
import { trimPercentage } from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'FieldBusinessPartner',
components: {
BusinessPartnerCreate,
BusinessPartnersList
},
props: {
parentMetadata: {
type: Object,
default: () => {}
},
showsPopovers: {
type: Object,
default: () => {
return {
isShowCreate: false,
isShowList: false
}
}
}
},
data() {
return {
controlDisplayed: this.displayedValue,
timeOut: null
}
},
computed: {
value: {
get() {
return this.$store.getters.getValueOfField({
containerUuid: this.parentMetadata.containerUuid,
columnName: 'C_BPartner_ID' // this.parentMetadata.columnName
})
},
set(value) {
this.$store.commit('updateValueOfField', {
containerUuid: this.parentMetadata.containerUuid,
columnName: 'C_BPartner_ID', // this.parentMetadata.columnName,
value
})
}
},
displayedValue: {
get() {
return this.$store.getters.getValueOfField({
containerUuid: this.parentMetadata.containerUuid,
// DisplayColumn_'ColumnName'
columnName: 'DisplayColumn_C_BPartner_ID' // this.parentMetadata.displayColumnName
})
},
set(value) {
this.$store.commit('updateValueOfField', {
containerUuid: this.parentMetadata.containerUuid,
// DisplayColumn_'ColumnName'
columnName: 'DisplayColumn_C_BPartner_ID', // this.parentMetadata.displayColumnName,
value
})
}
},
recordsBusinessPartners() {
return this.$store.getters.getBusinessPartnersList
},
blankBPartner() {
return {
uuid: undefined,
id: undefined,
name: undefined
}
}
},
methods: {
setBusinessPartner,
searchBPartnerList,
setNewDisplayedValue() {
const displayValue = this.displayedValue
if (this.controlDisplayed !== displayValue) {
this.controlDisplayed = displayValue
}
},
setOldDisplayedValue() {
if (this.controlDisplayed !== this.displayedValue) {
this.displayedValue = this.controlDisplayed
}
},
localSearch(stringToMatch, callBack) {
if (this.isEmptyValue(stringToMatch)) {
// not show list
callBack([])
return
}
const recordsList = this.recordsBusinessPartners
let results = recordsList
if (stringToMatch) {
const parsedValue = trimPercentage(stringToMatch.toLowerCase().trim())
results = recordsList.filter(rowBPartner => {
for (const columnBPartner in rowBPartner) {
const valueToCompare = String(rowBPartner[columnBPartner]).toLowerCase()
if (valueToCompare.includes(parsedValue)) {
return true
}
}
return false
})
// Remote search
if (this.isEmptyValue(results) && String(stringToMatch.length > 3)) {
clearTimeout(this.timeOut)
this.timeOut = setTimeout(() => {
this.remoteSearch(stringToMatch)
.then(remoteResponse => {
callBack(remoteResponse)
})
}, 2000)
return
}
}
// call callback function to return suggestions
callBack(results)
},
remoteSearch(searchValue) {
return new Promise(resolve => {
const message = {
message: 'Sin resultados coincidentes con la busqueda',
type: 'info',
showClose: true
}
this.$store.dispatch('listBPartnerFromServer', {
pageNumber: 1,
searchValue
})
.then(() => {
const recordsList = this.recordsBusinessPartners
if (this.isEmptyValue(recordsList)) {
this.$message(message)
}
resolve(recordsList)
})
.catch(error => {
console.warn(error.message)
this.$message(message)
resolve([])
})
})
},
handleSelect(selectedValue) {
let businessPartner = selectedValue
if (this.isEmptyValue(businessPartner)) {
businessPartner = this.blankBPartner
}
this.setBusinessPartner(businessPartner, false)
},
onClose() {
this.showsPopovers.isShowCreate = true
},
// TODO: Improve the handling of the event, if given an option to not search
getBPartnerWithEnter(event) {
const value = String(event.target.value).trim()
// Get one element
// this.getBPartner(value)
const createBP = () => {
this.$store.commit('updateValueOfField', {
containerUuid: 'Business-Partner-Create',
columnName: 'Name',
value
})
this.$store.commit('updateValueOfField', {
containerUuid: 'Business-Partner-Create',
columnName: 'Value',
value
})
this.showsPopovers.isShowList = false
this.showsPopovers.isShowCreate = true
}
this.searchBPartnerList({
searchValue: `%${value}%`
}, false)
.then(responseBPartnerList => {
const records = responseBPartnerList.length
if (records <= 0) {
// open create (without records)
createBP()
this.controlDisplayed = ''
} else if (records === 1) {
// set unique match
this.setBusinessPartner(responseBPartnerList[0], false)
this.controlDisplayed = responseBPartnerList[0].name
} else {
// show list with macth's
const columnName = 'Name' // Value
// if (Number.isNaN(Number(value))) {
// columnName = 'Name'
// }
this.$store.commit('updateValuesOfContainer', {
containerUuid: 'Business-Partner-List',
attributes: [{
columnName,
value: `%${value}%`
}]
})
this.showsPopovers.isShowList = true
this.showsPopovers.isShowCreate = false
}
})
.catch(error => {
// create bpartner with typing values
createBP()
console.warn(error)
})
},
getBPartner(value) {
if (this.isEmptyValue(value)) {
this.$message({
type: 'warning',
message: this.$t('notifications.fieldCannotBeEmpty'),
duration: 1500,
showClose: true
})
return
}
requestGetBusinessPartner({
searchValue: value
})
.then(responseBPartner => {
// set id, uuid and name
this.setBusinessPartner(responseBPartner, false)
})
.catch(error => {
const message = this.$t('businessPartner.notFound') + ' ' + this.$t('data.createNewRecord')
this.$message({
type: 'info',
message,
duration: 1500,
// showClose: true, // TODO: does not activate callback to display create form if closed with click
onClose: this.onClose
})
this.setBusinessPartner({
...this.blankBPartner,
name: value
})
this.$store.commit('updateValueOfField', {
containerUuid: 'Business-Partner-Create',
columnName: 'Name',
value
})
this.$store.commit('updateValueOfField', {
containerUuid: 'Business-Partner-Create',
columnName: 'Value',
value
})
console.info(`Error get Business Partner. Message: ${error.message}, code ${error.code}.`)
})
}
}
}
</script>
<style lang="scss" scope>
.custom-field-bpartner-info {
li {
line-height: normal;
padding: 15px;
.header {
text-overflow: ellipsis;
overflow: hidden;
}
.info {
color: #7e7e7e;
float: left;
font-size: 12px;
}
}
}
</style>

View File

@ -0,0 +1,141 @@
export default {
name: 'MixinBusinessPartner',
props: {
parentMetadata: {
type: Object,
default: () => {}
},
showsPopovers: {
type: Object,
default: () => {
return {
panelType: 'form',
isShowCreate: false,
isShowList: false
}
}
}
},
computed: {
shortsKey() {
return {
closeForm: ['esc'],
refreshListWithoutValues: ['shift', 'r'],
refreshList: ['f5']
}
}
},
methods: {
keyAction(event) {
switch (event.srcKey) {
case 'closeForm':
this.closeForm()
break
}
},
closeForm() {
this.showsPopovers.isShowList = false
this.showsPopovers.isShowCreate = false
},
/**
* ColumnName equals property to set into request's system-core
* @param {object} values
* @returns {object}
*/
convertValuesToSend(values) {
const valuesToSend = {}
Object.keys(values).forEach(key => {
const value = values[key]
if (this.isEmptyValue(value)) {
return
}
switch (key) {
case 'Code':
// Only used with search
valuesToSend['searchValue'] = value
break
case 'Value':
valuesToSend['value'] = value
break
case 'Name':
valuesToSend['name'] = value
break
case 'Contact':
valuesToSend['contactName'] = value
break
case 'EMail':
valuesToSend['eMail'] = value
break
case 'Phone':
valuesToSend['phone'] = value
break
// Location values
case 'C_Country_ID_UUID':
valuesToSend['countryUuid'] = value
break
case 'C_Region_ID_UUID':
valuesToSend['regionUuid'] = value
break
case 'DisplayColumn_C_Region_ID':
valuesToSend['regionName'] = value
break
case 'C_City_ID_UUID':
valuesToSend['cityUuid'] = value
break
case 'DisplayColumn_C_City_ID':
valuesToSend['cityName'] = value
break
case 'Address1':
valuesToSend['address1'] = value
break
case 'Address2':
valuesToSend['address2'] = value
break
case 'Address3':
valuesToSend['address3'] = value
break
case 'Address4':
valuesToSend['address4'] = value
break
case 'Postal':
valuesToSend['postalCode'] = value
break
}
})
valuesToSend['posUuid'] = this.$store.getters.getPointOfSalesUuid
return valuesToSend
},
setBusinessPartner({ id, name, uuid }, isCloseForm = true) {
const { parentUuid, containerUuid } = this.parentMetadata
// set ID value
this.$store.commit('updateValueOfField', {
parentUuid,
containerUuid,
columnName: 'C_BPartner_ID', // this.parentMetadata.columnName,
value: id
})
// set display column (name) value
this.$store.commit('updateValueOfField', {
parentUuid,
containerUuid,
// DisplayColumn_'ColumnName'
columnName: 'DisplayColumn_C_BPartner_ID', // this.parentMetadata.displayColumnName,
value: name
})
// set UUID value
this.$store.commit('updateValueOfField', {
parentUuid,
containerUuid,
columnName: 'C_BPartner_ID_UUID', // this.parentMetadata.columnName + '_UUID',
value: uuid
})
if (isCloseForm) {
this.closeForm()
}
}
}
}

View File

@ -0,0 +1,18 @@
const tableName = 'C_Order'
export default [
// Currency
{
tableName,
columnName: 'C_Currency_ID',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
handleActionKeyPerformed: true,
handleActionPerformed: true,
validationCode: 'C_Currency.C_Currency_ID = 100',
isActiveLogics: true,
isMandatory: true
}
}
]

View File

@ -0,0 +1,100 @@
<template>
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>
<b>
{{ $t('form.pos.collect.convertAmount') }}:
{{ formatPrice(amount * convert, displayCurrency) }}
</b>
</span>
</div>
<div class="text item">
<el-row>
<el-col :span="24">
<el-form
label-position="top"
label-width="10px"
style="float: right; display: flex; line-height: 10px;"
>
<span v-for="(field, index) in fieldsList" :key="index">
<field-definition
:key="field.columnName"
:metadata-field="field"
/>
</span>
</el-form>
</el-col>
</el-row>
</div>
</el-card>
</template>
<script>
import formMixin from '@/components/ADempiere/Form/formMixin'
import { formatPrice } from '@/utils/ADempiere/valueFormat.js'
import fieldsListConvertAmountCollection from './fieldsListConvertAmountCollection.js'
export default {
name: 'ConvertAmount',
mixins: [
formMixin
],
props: {
isAddTypePay: {
type: Array,
default: undefined
},
currency: {
type: Object,
default: undefined
},
amount: {
type: Number,
default: undefined
},
convert: {
type: Number,
default: undefined
},
metadata: {
type: Object,
default: () => {
return {
uuid: 'Collection-Convert-Amount',
containerUuid: 'Collection-Convert-Amount'
}
}
}
},
data() {
return {
fieldsList: fieldsListConvertAmountCollection
}
},
computed: {
displayCurrency() {
return this.$store.getters.getValueOfField({
containerUuid: this.containerUuid,
columnName: 'DisplayColumn_C_Currency_ID'
})
}
},
created() {
this.defaultValueCurrency()
},
methods: {
formatPrice,
defaultValueCurrency() {
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'DisplayColumn_C_Currency_ID',
value: this.currency.iSOCode
})
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'C_Currency_ID',
value: this.currency.id
})
}
}
}
</script>

View File

@ -0,0 +1,136 @@
const tableName = 'C_Payment'
export default [
// Amont
{
tableName,
columnName: 'PayAmt',
isFromDictionary: true,
overwriteDefinition: {
handleContentSelection: true,
handleActionPerformed: true,
size: 24,
isActiveLogics: true,
isMandatory: true
}
},
// TenderType
{
tableName,
columnName: 'TenderType',
isFromDictionary: true,
overwriteDefinition: {
defaultValue: 'X',
handleActionKeyPerformed: true,
handleContentSelection: true,
handleActionPerformed: true,
size: 8,
isActiveLogics: true,
isMandatory: true
}
},
// Bank
{
tableName,
columnName: 'C_Bank_ID',
isFromDictionary: true,
overwriteDefinition: {
handleActionKeyPerformed: true,
handleActionPerformed: true,
handleContentSelection: true,
displayLogic: `@TenderType@=='D'`,
size: 8,
isActiveLogics: true,
isMandatory: true
}
},
// Date
{
tableName,
elementColumnName: 'DateTrx',
isFromDictionary: true,
overwriteDefinition: {
handleActionKeyPerformed: true,
handleActionPerformed: true,
size: 8,
displayLogic: `@TenderType@=='K'`,
isActiveLogics: true,
isMandatory: true
}
},
// Currency
{
tableName: 'C_Order',
columnName: 'C_Currency_ID',
isFromDictionary: true,
overwriteDefinition: {
size: 8,
handleActionKeyPerformed: true,
handleActionPerformed: true,
validationCode: 'C_Currency.C_Currency_ID = 100',
isActiveLogics: true,
isMandatory: true
}
},
// ReferenceNo
{
tableName: 'HR_Attribute',
columnName: 'ReferenceNo',
isFromDictionary: true,
overwriteDefinition: {
handleActionKeyPerformed: true,
handleContentSelection: true,
handleActionPerformed: true,
displayLogic: `@TenderType@<>'X'&@TenderType@<>'C' `,
size: 8,
isActiveLogics: true,
isMandatory: true
}
},
// type credit card
{
tableName,
columnName: 'creditcardtype',
isFromDictionary: true,
overwriteDefinition: {
defaultValue: 'M',
handleActionKeyPerformed: true,
handleContentSelection: true,
handleActionPerformed: true,
size: 8,
displayLogic: `@TenderType@=='C'`,
isActiveLogics: true,
isMandatory: true
}
},
// number credit card
{
tableName,
columnName: 'creditcardnumber',
isFromDictionary: true,
overwriteDefinition: {
handleActionKeyPerformed: true,
handleContentSelection: true,
handleActionPerformed: true,
size: 8,
displayLogic: `@TenderType@=='C'`,
isActiveLogics: true,
isMandatory: true
}
},
// accountno
{
tableName,
columnName: 'accountno',
isFromDictionary: true,
overwriteDefinition: {
handleActionKeyPerformed: true,
handleContentSelection: true,
handleActionPerformed: true,
size: 8,
displayLogic: `@TenderType@=='M'`,
isActiveLogics: true,
isMandatory: true
}
}
]

View File

@ -0,0 +1,714 @@
<template>
<el-container style="background: white; height: 100% !important;">
<el-main style="background: white; padding: 0px; height: 100% !important; overflow: hidden">
<el-container style="background: white; padding: 0px; height: 100% !important;">
<el-header style="height: auto; padding-bottom: 10px; padding-right: 0px; padding-left: 0px">
<el-card class="box-card" style="padding-left: 0px; padding-right: 0px">
<div slot="header" class="clearfix">
<p class="total">
<b>{{ $t('form.pos.collect.orderTotal') }}:</b>
<b style="float: right;">
<el-popover
placement="top-start"
trigger="click"
>
<convert-amount
:convert="multiplyRate"
:amount="order.grandTotal"
:currency="currencyPoint"
/>
<el-button slot="reference" type="text" style="color: #000000;font-weight: 604!important;font-size: 100%;">
{{ formatPrice(order.grandTotal, currencyPoint.iSOCode) }}
</el-button>
</el-popover>
</b>
</p>
<p class="total">
<b> {{ $t('form.pos.collect.pending') }}: </b>
<b style="float: right;">
<el-popover
placement="top-start"
trigger="click"
>
<convert-amount
:convert="multiplyRate"
:amount="pending"
:currency="currencyPoint"
/>
<el-button slot="reference" type="text" style="color: #000000;font-weight: 604!important;font-size: 100%;">
{{ formatPrice(pending, currencyPoint.iSOCode) }}
</el-button>
</el-popover>
</b>
</p>
</div>
<div
v-if="isLoaded"
class="text item"
>
<el-form
label-position="top"
label-width="10px"
style="float: right; display: flex; line-height: 10px;"
>
<el-row>
<el-col v-for="(field, index) in fieldsList" :key="index" :span="8">
<field-definition
:key="field.columnName"
:metadata-field="field"
/>
</el-col>
</el-row>
</el-form>
</div>
</el-card>
<samp style="float: right;padding-right: 10px;">
<el-button type="danger" icon="el-icon-close" @click="cancel" />
<el-button type="primary" :disabled="isValidForPay || validateConvertion" icon="el-icon-plus" @click="addCollectToList(paymentBox)" />
</samp>
</el-header>
<el-main style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;">
<type-collection
v-if="isLoaded"
:is-add-type-pay="paymentBox"
:currency="currencyPoint"
/>
<div
v-else
key="form-loading"
v-loading="!isLoaded"
:element-loading-text="$t('notifications.loading')"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
class="loading-panel"
/>
</el-main>
<el-footer height="auto" style="padding-left: 0px; padding-right: 0px;">
<el-row :gutter="24" style="background-color: rgb(245, 247, 250);">
<el-col :span="24">
<span>
<p class="total">
<b>
{{ $t('form.pos.collect.orderTotal') }}:
</b>
<b style="float: right;">
<el-popover
placement="top-start"
trigger="click"
>
<convert-amount
:convert="multiplyRate"
:amount="order.grandTotal"
:currency="currencyPoint"
/>
<el-button slot="reference" type="text" style="color: #000000;font-weight: 604!important;font-size: 100%;">
{{ formatPrice(order.grandTotal, currencyPoint.iSOCode) }}
</el-button>
</el-popover>
</b>
</p>
<p class="total">
{{ $t('form.pos.collect.pending') }}:
<b style="float: right;">
<el-popover
placement="top-start"
trigger="click"
>
<convert-amount
:convert="multiplyRate"
:amount="pending"
:currency="currencyPoint"
/>
<el-button slot="reference" type="text" style="color: #000000;font-weight: 604!important;font-size: 100%;">
{{ formatPrice(pending, currencyPoint.iSOCode) }}
</el-button>
</el-popover>
</b>
</p>
<p class="total">
{{ $t('form.pos.collect.payment') }}:
<b style="float: right;">
<el-popover
placement="top-start"
trigger="click"
>
<convert-amount
:convert="multiplyRate"
:amount="pay"
:currency="currencyPoint"
/>
<el-button slot="reference" type="text" style="color: #000000;font-weight: 604!important;font-size: 100%;">
{{ formatPrice(pay, currencyPoint.iSOCode) }}
</el-button>
</el-popover>
</b>
</p>
<p class="total">
{{ $t('form.pos.collect.change') }}:
<b style="float: right;">
<el-popover
placement="top-start"
trigger="click"
>
<convert-amount
:convert="multiplyRate"
:amount="change"
:currency="currencyPoint"
/>
<el-button slot="reference" type="text" style="color: #000000;font-weight: 604!important;font-size: 100%;">
{{ formatPrice(change, currencyPoint.iSOCode) }}
</el-button>
</el-popover>
</b>
</p>
</span>
</el-col>
</el-row>
</el-footer>
</el-container>
</el-main>
</el-container>
</template>
<script>
import formMixin from '@/components/ADempiere/Form/formMixin'
import fieldsListCollection from './fieldsListCollection.js'
import typeCollection from '@/components/ADempiere/Form/VPOS/Collection/typeCollection'
import convertAmount from '@/components/ADempiere/Form/VPOS/Collection/convertAmount/index'
import { formatDate, formatPrice } from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'Collection',
components: {
typeCollection,
convertAmount
},
mixins: [
formMixin
],
props: {
isLoadedPanel: {
type: Boolean,
required: false
},
amount: {
type: Object,
default: undefined
},
metadata: {
type: Object,
default: () => {
return {
uuid: 'Collection',
containerUuid: 'Collection'
}
}
}
},
data() {
return {
isCustomForm: true,
currencyConversion: 1,
convertAllPayment: 1,
allPayCurrency: 0,
fieldsList: fieldsListCollection
}
},
computed: {
isPaymentBox() {
return this.$store.getters.getPaymentBox
},
paymentBox() {
const payment = this.isPaymentBox.filter(pay => {
return pay.isVisible
})
if (this.isEmptyValue(payment)) {
return []
}
return payment
},
cashPayment() {
const cash = this.isPaymentBox.filter(pay => {
return pay.tenderType === 'X'
})
return this.sumCash(cash)
},
isValidForPay() {
const containerUuid = this.containerUuid
const typePay = this.$store.getters.getValueOfField({
containerUuid,
columnName: 'TenderType'
})
const amount = this.$store.getters.getValueOfField({
containerUuid,
columnName: 'PayAmt'
})
const allChange = Number.parseFloat(amount + this.change).toFixed(2) - this.cashPayment
if (typePay !== 'X' && !this.isMandatory) {
if (this.cashPayment === this.change && this.pending === 0 || (allChange > 0 && this.pending === 0)) {
return true
}
return false
}
const cash = this.pending === 0 ? true : this.isMandatory
return cash
},
turned() {
const containerUuid = this.containerUuid
const amount = this.$store.getters.getValueOfField({
containerUuid,
columnName: 'PayAmt'
})
const typePay = this.$store.getters.getValueOfField({
containerUuid,
columnName: 'TenderType'
})
const allPay = this.cashPayment + amount
if (typePay !== 'X') {
if (allPay <= this.order.grandTotal) {
return false
}
return true
}
return false
},
isCashAmt() {
const cashAmt = this.paymentBox.map(item => {
if (item.tenderType === 'X') {
return item.payAmt
}
return 0
})
if (!this.isEmptyValue(cashAmt)) {
return cashAmt.reduce((accumulator, currentValue) => accumulator + currentValue)
}
return 0
},
isOtherPayAmt() {
const cashAmt = this.paymentBox.map(item => {
if (item.tenderType !== 'X') {
return item.payAmt
}
return 0
})
if (!this.isEmptyValue(cashAmt)) {
return cashAmt.reduce((accumulator, currentValue) => accumulator + currentValue)
}
return 0
},
pay() {
return this.sumCash(this.isPaymentBox)
},
pending() {
const missing = this.order.grandTotal - this.pay
if (this.pay > 0 && this.pay < this.order.grandTotal) {
return missing
}
const pending = this.order.grandTotal <= this.pay ? 0 : this.order.grandTotal
return pending
},
isMandatory() {
const containerUuid = this.containerUuid
const fieldsEmpty = this.$store.getters.getFieldsListEmptyMandatory({
containerUuid,
fieldsList: this.fieldsList
})
const amount = this.$store.getters.getValueOfField({
containerUuid,
columnName: 'PayAmt'
})
if (this.isEmptyValue(fieldsEmpty) && amount > 0) {
return false
}
return true
},
change() {
const missing = this.pay - this.order.grandTotal
if (this.pay > 0 && this.pay > this.order.grandTotal) {
return missing
}
return 0
},
order() {
return this.$store.getters.getFindOrder
},
currencyPoint() {
const currency = this.$store.getters.getCurrentPOS
if (!this.isEmptyValue(currency)) {
return currency.priceList.currency
}
return {
uuid: '',
iSOCode: '',
curSymbol: '',
id: 0
}
},
currentOrder() {
return this.$store.getters.getFindOrder
},
typeCurrency() {
return this.$store.getters.getValueOfField({
containerUuid: this.containerUuid,
columnName: 'C_Currency_ID'
})
},
currencyUuid() {
return this.$store.getters.getValueOfField({
containerUuid: this.containerUuid,
columnName: 'C_Currency_ID_UUID'
})
},
displayeTypeCurrency() {
return this.$store.getters.getValueOfField({
containerUuid: this.containerUuid,
columnName: 'DisplayColumn_C_Currency_ID'
})
},
multiplyRate() {
return this.$store.getters.getMultiplyRate
},
converCurrency() {
return this.$store.getters.getValueOfField({
containerUuid: 'Collection-Convert-Amount',
columnName: 'C_Currency_ID_UUID'
})
},
divideRate() {
return this.$store.getters.getDivideRate
},
fieldAmount() {
const amount = this.$store.getters.getValueOfField({
containerUuid: this.containerUuid,
columnName: 'PayAmt'
})
return amount * this.divideRate
},
validateConvertion() {
if (this.fieldAmount <= this.pending) {
return false
}
return true
}
// fieldpending() {
// return this.pending / this.divideRate
// }
},
watch: {
// fieldpending(value) {
// this.$store.commit('updateValueOfField', {
// containerUuid: this.containerUuid,
// columnName: 'PayAmt',
// value: value
// })
// },
pending(value) {
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'PayAmt',
value
})
},
currencyUuid(value) {
this.$store.dispatch('conversionDivideRate', {
conversionTypeUuid: this.$store.getters.getCurrentPOS.conversionTypeUuid,
currencyFromUuid: this.currencyPoint.uuid,
currencyToUuid: value,
conversionDate: this.currentOrder.dateOrdered
})
},
convertAllPayment(value) {
if (!this.isEmptyValue(value)) {
this.allPayCurrency = this.pay / value
}
this.allPayCurrency = this.pay
},
converCurrency(value) {
this.$store.dispatch('conversionMultiplyRate', {
conversionTypeUuid: this.$store.getters.getCurrentPOS.conversionTypeUuid,
currencyFromUuid: this.currencyPoint.uuid,
currencyToUuid: value,
conversionDate: this.currentOrder.dateOrdered
})
},
isLoaded(value) {
if (value) {
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'PayAmt',
value: this.pending
})
}
}
},
created() {
this.defaultValueCurrency()
},
methods: {
formatDate,
formatPrice,
sumCash(cash) {
let sum = 0
cash.forEach((pay) => {
sum += pay.payAmt
})
return sum
},
notSubmitForm(event) {
event.preventDefault()
return false
},
displayTenderType(type) {
let label
switch (type) {
case 'A':
label = 'Depósito directo'
break
case 'C':
label = 'Tarjeta de crédito'
break
case 'D':
label = 'Débito directo'
break
case 'K':
label = 'Cheque'
break
case 'M':
label = 'Nota de crédito'
break
case 'P':
label = 'Pago móvil interbancario'
break
case 'T':
label = 'Cuenta'
break
case 'X':
label = 'Efectivo'
break
case 'Z':
label = 'Zelle'
break
}
return label
},
addCollectToList() {
const containerUuid = this.containerUuid
const amount = this.$store.getters.getValueOfField({
containerUuid,
columnName: 'PayAmt'
})
const date = this.$store.getters.getValueOfField({
containerUuid,
columnName: 'DateTrx'
})
const typePay = this.$store.getters.getValueOfField({
containerUuid,
columnName: 'TenderType'
})
const referenceNo = this.$store.getters.getValueOfField({
containerUuid,
columnName: 'ReferenceNo'
})
let currency = this.$store.getters.getValueOfField({
containerUuid,
columnName: 'DisplayColumn_C_Currency_ID'
})
const currencyId = this.$store.getters.getValueOfField({
containerUuid,
columnName: 'C_Currency_ID'
})
if (currency === this.currencyPoint.id) {
currency = this.currencyPoint.iSOCode
}
const displayType = this.displayTenderType(typePay)
this.$store.dispatch('setPaymentBox', {
isVisible: true,
quantityCahs: amount,
payAmt: amount * this.divideRate,
tenderType: typePay,
referenceNo: referenceNo,
dateTrx: date,
currency: {
currency,
id: currencyId
},
displayTenderType: displayType
})
this.addCollect()
},
addCollect() {
this.fieldsList.forEach(element => {
if (element.columnName !== 'PayAmt') {
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: element.columnName,
value: element.defaultValue
})
// set default logics
this.$store.dispatch('changeDependentFieldsList', {
field: element
})
}
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'C_Currency_ID',
value: this.currencyPoint.id
})
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'PayAmt',
value: this.pending
})
})
this.defaultValueCurrency()
this.$store.dispatch('conversionDivideRate', 1)
},
cancel() {
this.fieldsList.forEach(element => {
if (element.columnName !== 'PayAmt' || element.columnName !== 'C_Currency_ID') {
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: element.columnName,
value: element.defaultValue
})
}
this.$store.dispatch('changeDependentFieldsList', {
field: element
})
})
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'C_Currency_ID',
value: this.currencyPoint.id
})
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'PayAmt',
value: this.pending
})
this.defaultValueCurrency()
this.$store.dispatch('conversionDivideRate', 1)
},
getPriceApplyingDiscount(price, discount) {
if (this.isEmptyValue(price)) {
price = 0
}
if (this.isEmptyValue(discount)) {
discount = 0
}
return price - discount * price / 100
},
getDiscountByPriceEntered(unitPrice, priceEntereded) {
if (this.isEmptyValue(unitPrice)) {
unitPrice = 0
}
if (this.isEmptyValue(priceEntereded)) {
priceEntereded = 0
}
const discount = 100 - priceEntereded * 100 / unitPrice
if (this.isEmptyValue(discount) || discount === -Infinity) {
return 0
}
return discount
},
defaultValueCurrency() {
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'DisplayColumn_C_Currency_ID',
value: this.currencyPoint.iSOCode
})
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'C_Currency_ID',
value: this.currencyPoint.id
})
this.$store.commit('updateValueOfField', {
containerUuid: this.containerUuid,
columnName: 'C_Currency_ID_UUID',
value: this.currencyPoint.uuid
})
}
}
}
</script>
<style scoped>
.el-button--text {
border-color: transparent;
color: #1890ff;
background: transparent;
padding-left: 0;
padding-right: 0;
padding-bottom: 0px;
padding-top: 0px;
}
.el-card__header {
padding: 18px 20px;
border-bottom: 1px solid #e6ebf5;
-webkit-box-sizing: border-box;
box-sizing: border-box;
background-color: rgb(245, 247, 250);
}
.delete-buttom {
border: none;
width: 100%;
text-align: left;
}
.el-col-24 {
width: 100%;
padding-right: 0px !important;
padding-left: 0px !important;
}
.el-col-6 {
padding-right: 0px !important;
padding-left: 0px !important;
}
.el-card__body {
padding-top: 0px !important;
padding-right: 0px!important;
padding-bottom: 20px;
padding-left: 10px!important;
height: 100%!important;
}
.el-card__header {
padding: 0px 20px;
border-bottom: 1px solid #e6ebf5;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.bottom {
margin-top: 13px;
line-height: 12px;
}
.button {
padding: 0;
float: right;
}
.el-header {
background: 'white';
color: #333;
line-height: 10px;
}
.el-aside {
color: #333;
}
.el-row {
margin: 0px!important;
}
.el-tag--medium {
height: 34px;
line-height: 32px;
}
.el-col {
border-radius: 4px;
}
</style>

View File

@ -0,0 +1,193 @@
<template>
<el-container style="background: white; height: 100% !important;">
<el-main style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;">
<el-row :gutter="24">
<template v-for="(value, key) in isAddTypePay">
<el-col v-if="value.isVisible" :key="key" :span="12" style="padding-left: 5px; padding-right: 5px;">
<el-card :body-style="{ padding: '0px' }">
<el-row>
<el-col :span="6" style="padding: 10px">
<img src="@/image/ADempiere/pos/no-image.jpg" fit="contain" class="image">
</el-col>
<el-col :span="18">
<el-button
type="text"
icon="el-icon-close"
style="float: right; margin-right: 10px; color: red; padding-top: 10px;"
@click="deleteCollect(key)"
/>
<div style="padding-right: 10px; padding-top: 10%;">
<div class="top clearfix">
<span>{{ value.displayTenderType }}</span>
</div>
<div class="bottom clearfix" style="margin-top: 0px !important!">
<el-button
type="text"
class="button"
style="color: rgb(50, 54, 58); font-size: 13px; text-align: left; float: unset; padding-top: 5px;"
>
{{ value.referenceNo }}
</el-button>
<el-button
v-if="!isEmptyValue(value.dateTrx)"
type="text"
class="button"
style="color: rgb(50, 54, 58); font-size: 13px; text-align: left; float: unset; padding-top: 5px;"
>
{{ formatDate(value.dateTrx) }}
</el-button>
<div slot="header" class="clearfix">
<p class="total" :style="value.currency.id === currency.id ? 'padding-top: 5%;' : ''">
<b style="float: right; padding-bottom: 10px">
{{ formatPrice(value.payAmt, currency.iSOCode) }}
</b>
</p>
<br>
<p v-if="value.currency.id !== currency.id" class="total">
<b style="float: right; padding-bottom: 10px">
{{ formatPrice(value.quantityCahs, value.currency.currency) }}
</b>
</p>
</div>
</div>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</template>
</el-row>
</el-main>
</el-container>
</template>
<script>
import {
formatDate,
formatPrice
} from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'TypeCollection',
props: {
isAddTypePay: {
type: Array,
default: undefined
},
currency: {
type: Object,
default: undefined
}
},
methods: {
formatDate,
formatPrice,
getImageFromTenderType(typePay) {
// A: Direct Deposit: ACH Automatic Clearing House
// C: Credit Card:
// D: Direct Debit:
// K: Check:
// M: Credit Memo:
// P: Mobile Payment Interbank:
// T: Account:
// X: Cash:
// Z: Zelle:
let image = ''
switch (typePay) {
case 'A':
image = 'DirectDeposit2'
break
case 'M':
image = 'CreditMemo'
break
case 'K':
image = 'check2'
break
case 'X':
image = 'cash'
break
case 'Z':
image = 'zelle'
break
case 'T':
image = 'Account'
break
case 'P':
image = 'paymobile'
break
case 'C':
image = 'CreditCard'
break
case 'D':
image = 'DirectDebit'
break
}
return require('@/image/' + image + '.jpg')
},
deleteCollect(key) {
this.$store.dispatch('deleteCollectBox', key)
}
}
}
</script>
<style scoped>
.el-image {
display: inline-block;
overflow: hidden;
}
.el-card__header {
padding: 18px 20px;
border-bottom: 1px solid #e6ebf5;
-webkit-box-sizing: border-box;
box-sizing: border-box;
background-color: rgb(245, 247, 250);
}
.el-card__body {
padding-top: 0px !important;
padding-right: 0px!important;
padding-bottom: 20px;
padding-left: 10px!important;
height: 100%!important;
}
.bottom {
margin-top: 0px!important;
line-height: 1px;
}
.button {
padding: 0;
float: right;
}
.image {
width: 100%;
display: block;
height: 9vh;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
.el-header {
background: 'white';
color: #333;
line-height: 10px;
}
.el-aside {
color: #333;
}
.el-row {
margin: 0px!important;
}
</style>

View File

@ -0,0 +1,351 @@
<template>
<el-container style="background: white; height: 100% !important;">
<el-header>
<div class="clearfix" style="padding: 0px; margin: 0px">
<el-row>
<el-col :span="20" style="padding-left: 20%; padding-right: 0px">
<p style="text-align: center; padding: 0px; margin: 0px;">
<b>{{ getLayoutHeader.name }}</b>
<br>
{{ getLayoutHeader.description }}
</p>
</el-col>
</el-row>
</div>
<el-button
icon="el-icon-s-home"
size="small"
style="float: right"
circle
@click="handleCommand"
/>
</el-header>
<el-main>
<el-card
v-if="!isEmptyValue(getKeyList)"
>
<el-row style="padding: 2px">
<template v-for="(keyValue, key) in getKeyList">
<el-col :key="key" :span="size">
<el-card
:body-style="{ padding: '0px' }"
:data="getImage(keyValue.resourceReference)"
shadow="always"
>
<span>
<p style="padding-left: 10px; font-size: 12px; color: #0e2ea4">
<b>{{ keyValue.name }}</b>
</p>
<!--
<b style="padding-left: 10px; font-size: 10px; color: #359e43">
Available
</b>
-->
</span>
<div @click="setKeyActionToOrderLine(keyValue)">
<el-image
v-if="ifImage(keyValue)"
:src="srcImage(keyValue)"
class="key-layout"
fit="contain"
/>
<vue-content-loading v-else :width="300" :height="300" />
</div>
<div class="footer-product">
<p class="quantity">
Cantidad: {{ formatQuantity(keyValue.quantity) }}
</p>
<br>
</div>
</el-card>
</el-col>
</template>
</el-row>
</el-card>
<el-card v-else>
<el-image
:src="defaultImage"
class="error-layout"
fit="contain"
/>
<div class="error-product">
<el-link
@click="handleCommand"
>
{{ $t('form.pos.keyLayout.noProducto') }}
<i class="el-icon-s-home" />
</el-link>
</div>
</el-card>
</el-main>
</el-container>
</template>
<script>
import VueContentLoading from '@/components/ADempiere/ContentLoader'
import { requestImage } from '@/api/ADempiere/persistence.js'
import { buildImageFromArrayBuffer } from '@/utils/ADempiere/resource.js'
import { formatQuantity } from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'KeyLayout',
components: {
VueContentLoading
},
data() {
return {
resource: {},
isLoadedKeyLayout: false,
valuesImage: [{
identifier: 'undefined',
value: '',
isLoaded: true
}]
}
},
computed: {
defaultImage() {
return require('@/image/ADempiere/pos/no-image.jpg')
},
currentPoint() {
return this.$store.getters.getCurrentPOS
},
listOrderLine() {
return this.$store.getters.getListOrderLine
},
getKeyLayout() {
return this.$store.getters.getKeyLayout
},
getKeyList() {
return this.getKeyLayout.keysList
},
getLayoutHeader() {
const keyLayout = this.getKeyLayout
if (keyLayout) {
return keyLayout
}
return {
name: undefined,
description: undefined
}
},
// TODO: Verify with panel collection
isShowedPOSKeyLayout() {
return this.$store.getters.getShowPOSKeyLayout
},
isReadyFromGetData() {
const { isLoaded, isReload } = this.getKeyLayout
return (!isLoaded || isReload) && this.isShowedPOSKeyLayout
},
size() {
const size = this.$store.getters.getWidthRight
return 24 / size
}
},
watch: {
isReadyFromGetData(isToLoad) {
if (isToLoad) {
this.loadKeyLayout()
}
}
},
mounted() {
if (this.isReadyFromGetData) {
this.loadKeyLayout()
}
},
methods: {
formatQuantity,
loadKeyLayout(uuid = null) {
const currentPOS = this.currentPoint
if (this.isEmptyValue(currentPOS) || this.isEmptyValue(currentPOS.uuid)) {
this.$message({
type: 'warn',
message: 'Without POS Terminal',
shosClose: true
})
return
}
this.$store.dispatch('getKeyLayoutFromServer', uuid)
.then(() => {
this.isLoadedKeyLayout = true
})
},
getImage(resource) {
if (this.isEmptyValue(resource) || this.isEmptyValue(resource.fileName)) {
return
}
const { fileName, contentType } = resource
if (!this.valuesImage.some(item => item.identifier === fileName)) {
this.valuesImage.push({
identifier: fileName,
value: '',
isLoaded: false
})
}
if (this.resource[fileName]) {
this.valuesImage.forEach(item => {
if (item.identifier === fileName) {
item.value = this.resource[fileName]
item.isLoaded = true
}
})
} else { // Reload
if (!this.valuesImage.some(item => item.identifier === fileName)) {
this.valuesImage.push({
identifier: fileName,
value: '',
isLoaded: false
})
}
requestImage({
file: fileName
}).then(responseImage => {
const arrayBufferAsImage = buildImageFromArrayBuffer({
arrayBuffer: responseImage,
contentType
})
this.resource[fileName] = arrayBufferAsImage
this.valuesImage.forEach(item => {
if (item.identifier === fileName) {
item.value = arrayBufferAsImage
item.isLoaded = true
}
})
})
}
},
setKeyActionToOrderLine(keyValue) {
if (!this.isEmptyValue(keyValue.subKeyLayoutUuid)) {
this.loadKeyLayout(keyValue.subKeyLayoutUuid)
} else {
const products = this.listOrderLine.find(item => item.lineDescription === keyValue.name)
// TODO: Change this dispatch
if (!this.isEmptyValue(products) && keyValue.quantity > 1) {
this.$store.dispatch('notifyActionKeyPerformed', {
value: {
QtyEntered: keyValue.quantity,
value: keyValue.name
}
})
} else {
this.$store.dispatch('notifyActionKeyPerformed', {
columnName: 'ProductValue',
value: {
QtyEntered: keyValue.quantity,
value: keyValue.name
}
})
}
}
},
handleCommand(command) {
const point = this.$store.getters.getPointOfSalesUuid.keyLayoutUuid
const toReturn = this.getKeyList.find(keyLayoutItem => keyLayoutItem.subKeyLayoutUuid === point)
let keyLayoutUuid = this.currentPoint.keyLayoutUuid
if (!this.isEmptyValue(toReturn)) {
keyLayoutUuid = toReturn.subKeyLayoutUuid
}
this.loadKeyLayout(keyLayoutUuid)
},
ifImage(keyValue) {
const { fileName } = keyValue.resourceReference
if (this.isEmptyValue(fileName)) {
return true
}
const image = this.valuesImage.find(item => item.identifier === fileName)
if (this.isEmptyValue(image)) {
return false
}
return image.isLoaded
},
srcImage(keyValue) {
const { fileName } = keyValue.resourceReference
if (this.isEmptyValue(fileName)) {
return this.defaultImage
}
// const image = this.valuesImage.find(item => item.identifier === fileName).value
const image = this.resource[fileName]
if (this.isEmptyValue(image)) {
return this.defaultImage
}
return image
}
}
}
</script>
<style lang="scss" scoped>
.el-card__header {
padding: 0px !important;
border-bottom: 1px solid #e6ebf5;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.key-layout {
width: 100%;
height: 200px;
display: block;
padding-top: 10px;
padding-right: 10px;
padding-bottom: 10px;
padding-left: 10px;
}
.error-layout {
width: 100%;
height: 25%;
display: block;
padding-top: 10px;
padding-right: 10px;
padding-bottom: 10px;
padding-left: 10px;
}
.price {
height: 100%;
font-size: 15px;
width: 50%;
text-align: right;
padding: 0px !important;
margin-top: 5px !important;
margin-bottom: 10px !important;
margin-left: 0px !important;
margin-right: 7px !important;
}
.quantity {
height: 100%;
font-size: 13px;
text-align: left;
width: 50%;
padding: 0px !important;
margin-top: 5px !important;
margin-bottom: 10px !important;
margin-left: 7px !important;
margin-right: 0px !important;
}
.footer-product {
display: flex;
width: 100%;
}
.error-product {
width: 100%;
text-align: center;
}
.el-main {
display: block;
box-sizing: border-box;
padding-top: 5px !important;
padding-bottom: 5px !important;
padding-left: 5px !important;
padding-right: 5px !important;
}
</style>

View File

@ -0,0 +1,456 @@
<template>
<div>
<div style="text-align: center">
<b>{{ $t('form.pos.title') }}</b>
<br>
{{ $t('form.pos.optionsPoinSales.title') }}
</div>
<el-collapse v-model="activeName" accordion>
<el-collapse-item :title="$t('form.pos.optionsPoinSales.salesOrder.title')" name="salesOrder">
<el-row :gutter="12" style="padding-right: 10px;">
<el-col :span="size">
<el-card shadow="hover">
<p
:style="isEmptyValue($route.query.action) ? 'cursor: not-allowed; text-align: center !important; color: gray;' : blockOption"
@click="newOrder"
>
<i class="el-icon-news" />
<br>
{{ $t('form.pos.optionsPoinSales.salesOrder.newOrder') }}
</p>
</el-card>
</el-col>
<el-col :span="size">
<el-card shadow="hover">
<el-popover
v-model="isShowOrdersList"
placement="right"
width="800"
trigger="click"
>
<orders-list
v-if="isShowOrdersList"
:parent-metadata="metadata"
/>
<p
slot="reference"
:style="blockOption"
>
<svg-icon icon-class="list" />
<br>
{{ $t('form.pos.optionsPoinSales.salesOrder.ordersHistory') }}
</p>
</el-popover>
</el-card>
</el-col>
<el-col :span="size">
<el-card shadow="hover">
<p
:style="blockOption"
@click="generateImmediateInvoice"
>
<i class="el-icon-document-add" />
<br>
{{ $t('form.pos.optionsPoinSales.salesOrder.generateImmediateInvoice') }}
</p>
</el-card>
</el-col>
<el-col :span="size">
<el-card shadow="hover">
<p
:style="blockOption"
@click="completePreparedOrder"
>
<i class="el-icon-success" />
<br>
{{ $t('form.pos.optionsPoinSales.salesOrder.completePreparedOrder') }}
</p>
</el-card>
</el-col>
<el-col :span="size">
<el-card shadow="hover">
<p
:style="blockOption"
@click="reverseSalesTransaction"
>
<i class="el-icon-error" />
<br>
{{ $t('form.pos.optionsPoinSales.salesOrder.cancelSaleTransaction') }}
</p>
</el-card>
</el-col>
<el-col :span="size">
<el-card shadow="hover">
<p
:style="blockOption"
@click="createWithdrawal"
>
<i class="el-icon-document-remove" />
<br>
{{ $t('form.pos.optionsPoinSales.salesOrder.createPos') }}
</p>
</el-card>
</el-col>
<el-col :span="size">
<el-card shadow="hover">
<p
:style="blockOption"
@click="printOrder"
>
<i class="el-icon-printer" />
<br>
{{ $t('form.pos.optionsPoinSales.salesOrder.toPrint') }}
</p>
</el-card>
</el-col>
<el-col :span="size">
<el-card shadow="hover">
<p
:style="blockOption"
@click="createNewCustomerReturnOrder"
>
<i class="el-icon-refresh-left" />
<br>
Crear Nueva Orden de Devolución
</p>
</el-card>
</el-col>
</el-row>
</el-collapse-item>
<el-collapse-item :title="$t('form.pos.optionsPoinSales.cashManagement.title')" name="cashManagement">
<el-row :gutter="12" style="padding-right: 10px;">
<el-col :span="size">
<el-card shadow="hover">
<p
:style="blockOption"
>
<i class="el-icon-sell" />
<br>
{{ $t('form.pos.optionsPoinSales.cashManagement.cashOpening') }}
</p>
</el-card>
</el-col>
<el-col :span="size">
<el-card shadow="hover">
<p
:style="blockOption"
>
<i class="el-icon-money" />
<br>
{{ $t('form.pos.optionsPoinSales.cashManagement.cashwithdrawal') }}
</p>
</el-card>
</el-col>
<el-col :span="size">
<el-card shadow="hover">
<p
:style="blockOption"
@click="cashClosing"
>
<i class="el-icon-sold-out" />
<br>
{{ $t('form.pos.optionsPoinSales.cashManagement.closeBox') }}
</p>
</el-card>
</el-col>
</el-row>
</el-collapse-item>
<el-collapse-item :title="$t('form.pos.optionsPoinSales.generalOptions.title')" name="generalOptions">
<el-row :gutter="12" style="padding-right: 10px;">
<!--
<el-col :span="size">
<el-card shadow="hover">
<el-popover
placement="right"
width="400"
trigger="click"
>
<el-form label-position="top" label-width="10px" @submit.native.prevent="notSubmitForm">
<field
:key="typeDocumentMetadata.columnName"
:metadata-field="typeDocumentMetadata"
:v-model="typeDocumentMetadata.value"
style="padding-left: 0px; padding-right: 0px;"
/>
</el-form>
<p slot="reference" :style="blockOption">
<i class="el-icon-document-copy" />
<br>
Cambiar Tipo de Documento
</p>
</el-popover>
</el-card>
</el-col>
-->
<el-col :span="size">
<el-card shadow="hover">
<el-dropdown trigger="click" style="padding-top: 8px; color: black;" @command="changePos">
<p
:style="blockOption"
>
<i class="el-icon-mobile-phone" />
<br>
{{ $t('form.pos.optionsPoinSales.generalOptions.changePos') }}
</p>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="item in sellingPointsList"
:key="item.uuid"
:command="item"
>
{{ item.name }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-card>
</el-col>
<el-col :span="8">
<el-card shadow="hover">
<el-popover
v-model="isShowProductsPriceList"
placement="right"
width="800"
trigger="manual"
>
<list-product-price
v-if="isShowProductsPriceList"
:is-selectable="false"
popover-name="isShowPopoverMenu"
/>
<div
slot="reference"
:style="blockOption"
@click="isShowProductsPriceList = !isShowProductsPriceList"
>
<svg-icon icon-class="shopping" />
<br>
{{ $t('form.pos.optionsPoinSales.generalOptions.listProducts') }}
</div>
</el-popover>
</el-card>
</el-col>
</el-row>
</el-collapse-item>
</el-collapse>
</div>
</template>
<script>
import OrdersList from '@/components/ADempiere/Form/VPOS/OrderList/index'
import ListProductPrice from '@/components/ADempiere/Form/VPOS/ProductInfo/productList'
import {
requestPrintOrder,
requestGenerateImmediateInvoice,
requestCompletePreparedOrder,
requestReverseSalesTransaction,
requestCreateWithdrawal,
requestCreateNewCustomerReturnOrder,
requestCashClosing
} from '@/api/ADempiere/form/point-of-sales.js'
export default {
name: 'Options',
components: {
ListProductPrice,
OrdersList
},
props: {
metadata: {
type: Object,
default: () => {}
}
},
data() {
return {
activeName: ''
}
},
computed: {
isShowProductsPriceList: {
get() {
return this.$store.state['pointOfSales/listProductPrice'].productPrice.isShowPopoverMenu
},
set(isShowed) {
if (!this.isEmptyValue(this.$route.query.pos)) {
this.$store.commit('showListProductPrice', {
attribute: 'isShowPopoverMenu',
isShowed
})
}
}
},
isShowOrdersList: {
get() {
return this.$store.getters.getListOrder.isShowPopover
},
set(value) {
if (!this.isEmptyValue(this.$route.query.pos)) {
this.$store.commit('showListOrders', value)
}
}
},
sellingPointsList() {
return this.$store.getters.getSellingPointsList
},
currentPOS() {
return this.$store.getters.getCurrentPOS
},
pointOfSalesId() {
const currentPOS = this.currentPOS
if (!this.isEmptyValue(currentPOS)) {
return currentPOS.id
}
return undefined
},
blockOption() {
if (!this.isEmptyValue(this.$route.query.pos)) {
return 'cursor: pointer; text-align: center !important; color: black'
}
return 'cursor: not-allowed; text-align: center !important; color: gray;'
},
size() {
const size = this.$store.getters.getWidthLeft
return 24 / size
}
},
methods: {
notSubmitForm(event) {
event.preventDefault()
return false
},
changePos(posElement) {
this.$store.dispatch('setCurrentPOS', posElement)
this.newOrder()
},
newOrder() {
this.$store.dispatch('findOrderServer', {})
const pos = this.pointOfSalesId || this.$route.query.pos
this.$router.push({
params: {
...this.$route.params
},
query: {
pos
}
}).catch(error => {
console.info(`VPOS/Options component (New Order): ${error.message}`)
}).finally(() => {
const { templateBusinessPartner } = this.currentPOS
this.$store.commit('updateValuesOfContainer', {
containerUuid: this.metadata.containerUuid,
attributes: [{
columnName: 'UUID',
value: undefined
},
{
columnName: 'ProductValue',
value: undefined
},
{
columnName: 'C_BPartner_ID',
value: templateBusinessPartner.id
},
{
columnName: 'DisplayColumn_C_BPartner_ID',
value: templateBusinessPartner.name
},
{
columnName: ' C_BPartner_ID_UUID',
value: templateBusinessPartner.uuid
}]
})
// TODO: Set order with POS Terminal default values
// this.order = {
// documentType: {},
// documentStatus: {},
// salesRepresentative: this.currentPOS.salesRepresentative
//
this.$store.dispatch('listOrderLine', [])
})
},
printOrder() {
requestPrintOrder({
orderUuid: this.$route.query.action
})
},
generateImmediateInvoice() {
// TODO: Add BPartner
const { uuid: posUuid, id: posId } = this.getCurrentPOS
requestGenerateImmediateInvoice({
posId,
posUuid
})
},
completePreparedOrder() {
requestCompletePreparedOrder({
orderUuid: this.$route.query.action
})
},
reverseSalesTransaction() {
// TODO: Add BPartner
requestReverseSalesTransaction({
orderUuid: this.$route.query.action
})
},
createWithdrawal() {
const { uuid: posUuid, id: posId } = this.getCurrentPOS
// TODO: Add BParner, C_BankAccount_ID (caja), CashTransferBankAccount_ID, PAY_C_BankAccount_ID
requestCreateWithdrawal({
posId,
posUuid
})
},
createNewCustomerReturnOrder() {
requestCreateNewCustomerReturnOrder({
orderUuid: this.$route.query.action
})
},
cashClosing() {
const { uuid: posUuid, id: posId } = this.getCurrentPOS
requestCashClosing({
posId,
posUuid
})
}
}
}
</script>
<style lang="scss" scoped>
.el-button--text {
border-color: transparent;
color: black;
background: transparent;
padding-left: 0;
padding-right: 0;
}
.el-button--text:hover, .el-button--text:focus {
color: #46a6ff !important;
border-color: transparent;
background-color: transparent;
}
.el-col :hover {
background-color: rgba(209, 233, 255, 0.719);
}
.title-of-option {
cursor: pointer;
text-align: center !important;
}
</style>

View File

@ -0,0 +1,51 @@
export default [
// Product Code
{
elementColumnName: 'ProductValue',
columnName: 'ProductValue',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
sequence: 10,
handleActionKeyPerformed: true
}
},
{
elementColumnName: 'QtyEntered',
columnName: 'QtyEntered',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
sequence: 8,
handleActionPerformed: true,
handleContentSelection: true,
handleActionKeyPerformed: true
}
},
{
elementColumnName: 'PriceEntered',
columnName: 'PriceEntered',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
sequence: 9,
isReadOnly: true,
handleActionPerformed: true,
handleContentSelection: true,
handleActionKeyPerformed: true
}
},
{
elementColumnName: 'Discount',
columnName: 'Discount',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
sequence: 10,
isReadOnly: true,
handleActionPerformed: true,
handleContentSelection: true,
handleActionKeyPerformed: true
}
}
]

View File

@ -0,0 +1,570 @@
<template>
<div
v-if="isLoaded"
id="headerContainer"
style="display: -webkit-box; height: 100%"
>
<el-container style="background: white; height: 100%!important;">
<el-header
height="auto"
:style="isShowedPOSKeyLayout ? 'padding-right: 20px; padding-left: 0px;' : 'padding-right: 0px; padding-left: 0px;'"
>
<el-form label-position="top" label-width="10px" @submit.native.prevent="notSubmitForm">
<el-row :gutter="24">
<el-col :span="14" style="padding-left: 0px; padding-right: 0px;">
<template
v-for="(field) in fieldsList"
>
<product-info
v-if="field.columnName === 'ProductValue'"
:key="field.columnName"
:metadata="field"
/>
</template>
</el-col>
<el-col :span="6" style="padding-left: 2px; padding-right: 2px;">
<business-partner
:parent-metadata="{
name: panelMetadata.name,
containerUuid: panelMetadata.containerUuid,
uuid: panelMetadata.uuid,
panelType: panelMetadata.panelType
}"
/>
</el-col>
<el-col :span="2" :style="styleTab">
<el-tag
:type="tagStatus(order.documentStatus.value)"
>
<span v-if="isEmptyValue(order.documentStatus.value)">
Borrador
</span>
{{ order.documentStatus.name }}
</el-tag>
</el-col>
</el-row>
</el-form>
</el-header>
<el-main style="background: white; padding: 0px; height: 100% !important; overflow: hidden">
<el-container style="background: white; padding: 0px; height: 100% !important;">
<el-main style="padding-top: 0px; padding-right: 10px; padding-bottom: 0px; padding-left: 10px;">
<el-table
ref="linesTable"
:data="allOrderLines"
border
style="width: 100%; max-width: 100%; background-color: #FFFFFF; font-size: 14px; overflow: auto; color: #606266;"
highlight-current-row
fit
@current-change="handleCurrentLineChange"
>
<el-table-column
v-for="(valueOrder, item, key) in orderLineDefinition"
:key="key"
:column-key="valueOrder.columnName"
:label="valueOrder.label"
:width="valueOrder.isNumeric ? 'auto' : '380'"
:align="valueOrder.isNumeric ? 'right' : 'left'"
>
<template slot-scope="scope">
<span>
{{ displayValue(scope.row, valueOrder) }}
</span>
</template>
</el-table-column>
<el-table-column
label=""
width="120"
>
<template slot-scope="scope">
<el-dropdown trigger="click" @command="changeLine">
<span class="el-dropdown-link">
{{ $t('form.pos.tableProduct.options') }}
<i class="el-icon-arrow-down el-icon--right" />
</span>
<el-dropdown-menu slot="dropdown" style="padding-bottom: 0px;">
<el-dropdown-item icon="el-icon-info" :command="scope.row">
<el-popover
placement="right"
trigger="click"
:title="$t('form.pos.product.productInformation')"
>
<el-form
label-position="top"
label-width="60px"
style="float: right; display: flex; line-height: 30px;"
>
<el-row :gutter="24">
<el-col :span="4">
<div>
<el-avatar shape="square" :size="100" src="https://#" @error="true">
<el-image>
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline" />
</div>
</el-image>
</el-avatar>
</div>
</el-col>
<el-col :span="10">
{{ $t('form.pos.product.code') }}: <b>{{ currentOrderLine.product.value }}</b><br>
{{ $t('form.pos.product.name') }}: <b>{{ currentOrderLine.product.name }}</b><br>
{{ $t('form.pos.product.description') }}: <b>{{ currentOrderLine.product.description }}</b><br>
</el-col>
<el-col :span="10">
<div style="float: right">
{{ $t('form.pos.product.price') }}:
<b>{{ formatPrice(currentOrderLine.product.priceStandard, currencyPoint.iSOCode) }}</b>
<br>
{{ $t('form.pos.product.taxRate') }}:
<b>{{ currentOrderLine.taxIndicator }}</b>
<br>
{{ $t('form.pos.product.quantityAvailable') }}:
<b>{{ formatQuantity(currentOrderLine.quantityOrdered) }}</b>
</div>
</el-col>
</el-row>
</el-form>
<el-button slot="reference" type="text">
{{ $t('form.pos.product.productInformation') }}
</el-button>
</el-popover>
</el-dropdown-item>
<el-dropdown-item icon="el-icon-edit" :command="$t('form.pos.tableProduct.editQuantities')">
<el-popover
placement="right"
trigger="click"
:title="$t('form.pos.tableProduct.editQuantities')"
>
<el-row>
<el-col :span="8">
<el-form label-position="top" label-width="10px" @submit.native.prevent="notSubmitForm">
<template
v-for="(field) in fieldsList"
>
<field-definition
v-if="field.columnName === 'PriceEntered'"
:key="field.columnName"
:metadata-field="field"
/>
</template>
</el-form>
</el-col>
<el-col :span="8">
<el-form label-position="top" label-width="10px" @submit.native.prevent="notSubmitForm">
<template
v-for="(field) in fieldsList"
>
<field-definition
v-if="field.columnName === 'QtyEntered'"
:key="field.columnName"
:metadata-field="field"
/>
</template>
</el-form>
</el-col>
<el-col :span="8">
<el-form label-position="top" label-width="10px" @submit.native.prevent="notSubmitForm">
<template
v-for="(field) in fieldsList"
>
<field-definition
v-if="field.columnName === 'Discount'"
:key="field.columnName"
:metadata-field="field"
/>
</template>
</el-form>
</el-col>
</el-row>
<el-button slot="reference" type="text">
{{ $t('form.pos.tableProduct.editQuantities') }}
</el-button>
</el-popover>
</el-dropdown-item>
<el-button type="danger" icon="el-icon-delete" class="delete-buttom" plain @click="deleteOrderLine(scope.row)">
{{ $t('form.pos.tableProduct.remove') }}
</el-button>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer class="footer-table">
<div class="keypad">
<el-button type="primary" icon="el-icon-top" @click="arrowTop" />
<el-button type="primary" icon="el-icon-bottom" @click="arrowBottom" />
<el-button v-show="isValidForDeleteLine(allOrderLines)" type="danger" icon="el-icon-delete" @click="deleteOrderLine(currentOrderLine)" />
<el-button
v-show="isValidForDeleteLine(allOrderLines)"
type="success"
icon="el-icon-bank-card"
@click="openCollectionPanel"
>
{{ $t('form.pos.order.collect') }}
</el-button>
<br>
<p>
<el-dropdown
trigger="click"
style="padding-top: 8px; color: black;"
@command="changePos"
>
<p>
<i class="el-icon-mobile-phone" />
{{ $t('form.pos.order.pointSale') }}: <b style="cursor: pointer"> {{ namePointOfSales }} </b>
</p>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="item in sellingPointsList"
:key="item.uuid"
:command="item"
>
{{ item.name }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</p>
</div>
<span style="float: right;">
<p class="total">{{ $t('form.pos.order.seller') }}:<b style="float: right;">
{{ order.salesRepresentative.name }}
</b></p>
<p class="total"> {{ $t('form.pos.order.subTotal') }}:<b class="order-info">{{ formatPrice(order.totalLines, currencyPoint.iSOCode) }}</b></p>
<p class="total"> {{ $t('form.pos.order.discount') }}:<b class="order-info">{{ formatPrice(0, currencyPoint.iSOCode) }}</b> </p>
<p class="total"> {{ $t('form.pos.order.tax') }}:<b style="float: right;">{{ getOrderTax(currencyPoint.iSOCode) }}</b> </p>
<p class="total"><b>{{ $t('form.pos.order.total') }}:</b><b style="float: right;">{{ formatPrice(order.grandTotal, currencyPoint.iSOCode) }}</b></p>
</span>
<span style="float: right;padding-right: 40px;">
<p class="total">{{ $t('form.pos.order.order') }}: <b class="order-info">{{ order.documentNo }}</b></p>
<p class="total">
{{ $t('form.pos.order.date') }}:
<b class="order-info">
{{ orderDate }}
</b>
</p>
<p class="total">{{ $t('form.pos.order.type') }}:<b class="order-info">{{ order.documentType.name }}</b></p>
<p class="total">
{{ $t('form.pos.order.itemQuantity') }}
<b class="order-info">
{{ getItemQuantity }}
</b>
</p>
<p class="total">
{{ $t('form.pos.order.numberLines') }}
<b class="order-info">
{{ numberOfLines }}
</b></p>
</span>
</el-footer>
</el-container>
</el-main>
</el-container>
<div style="position: relative;padding-top: 30vh; z-index: 100;">
<el-button
:circle="true"
type="primary"
:icon="isShowedPOSKeyLayout ? 'el-icon-arrow-right' : 'el-icon-arrow-left'"
@click="isShowedPOSKeyLayout = !isShowedPOSKeyLayout"
/>
</div>
</div>
<div
v-else
key="form-loading"
v-loading="!isLoaded"
:element-loading-text="$t('notifications.loading')"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.8)"
class="view-loading"
/>
</template>
<script>
import formMixin from '@/components/ADempiere/Form/formMixin.js'
import orderLineMixin from './orderLineMixin.js'
import fieldsListOrder from './fieldsListOrder.js'
import posMixin from '@/components/ADempiere/Form/VPOS/posMixin.js'
import BusinessPartner from '@/components/ADempiere/Form/VPOS/BusinessPartner'
import ProductInfo from '@/components/ADempiere/Form/VPOS/ProductInfo'
export default {
name: 'Order',
components: {
BusinessPartner,
ProductInfo
},
mixins: [
formMixin,
orderLineMixin,
posMixin
],
data() {
return {
fieldsList: fieldsListOrder
}
},
computed: {
isShowedPOSKeyLayout: {
get() {
return this.$store.getters.getShowPOSKeyLayout
},
set(val) {
this.$store.commit('setShowPOSKeyLayout', val)
}
},
styleTab() {
const isShowedPOSOptions = this.$store.getters.getIsShowPOSOptions
if (this.isShowedPOSKeyLayout || isShowedPOSOptions) {
return 'adding-left: 0px; padding-right: 0px; padding-top: 3.5%;'
}
return 'padding-left: 30px; padding-right: 0px; padding-top: 2.2%;'
},
namePointOfSales() {
const currentPOS = this.$store.getters.getCurrentPOS
if (currentPOS && !this.isEmptyValue(currentPOS.name)) {
return currentPOS.name
}
return undefined
},
sellingPointsList() {
return this.$store.getters.getSellingPointsList
},
orderDate() {
if (this.isEmptyValue(this.order) || this.isEmptyValue(this.order.dateOrdered)) {
return this.formatDate(new Date())
}
return this.formatDate(this.order.dateOrdered)
},
getItemQuantity() {
if (this.isEmptyValue(this.currentOrder)) {
return 0
}
const result = this.allOrderLines.map(order => {
return order.quantityOrdered
})
if (!this.isEmptyValue(result)) {
return result.reduce((accumulator, currentValue) => {
return accumulator + currentValue
})
}
return 0
},
numberOfLines() {
if (this.isEmptyValue(this.currentOrder)) {
return
}
return this.allOrderLines.length
},
currencyPoint() {
const currency = this.currentPoint
if (!this.isEmptyValue(currency)) {
return currency.priceList.currency
}
return {
uuid: '',
iSOCode: '',
curSymbol: ''
}
}
},
methods: {
changePos(posElement) {
this.$store.dispatch('setCurrentPOS', posElement)
this.newOrder()
},
openCollectionPanel() {
this.$store.commit('setShowPOSCollection', !this.$store.getters.getShowCollectionPos)
this.isShowedPOSKeyLayout = true
this.$store.commit('setShowPOSOptions', false)
},
newOrder() {
this.$store.dispatch('findOrderServer', {})
this.$router.push({
params: {
...this.$route.params
},
query: {
pos: this.currentPoint.id
}
}).catch(() => {
}).finally(() => {
const { templateBusinessPartner } = this.currentPoint
this.$store.commit('updateValuesOfContainer', {
containerUuid: this.metadata.containerUuid,
attributes: [{
columnName: 'UUID',
value: undefined
},
{
columnName: 'ProductValue',
value: undefined
},
{
columnName: 'C_BPartner_ID',
value: templateBusinessPartner.id
},
{
columnName: 'DisplayColumn_C_BPartner_ID',
value: templateBusinessPartner.name
},
{
columnName: ' C_BPartner_ID_UUID',
value: templateBusinessPartner.uuid
}]
})
this.$store.dispatch('listOrderLine', [])
})
}
}
}
</script>
<style scoped>
.delete-buttom {
border: none;
width: 100%;
text-align: left;
}
.el-col-24 {
width: 100%;
padding-right: 0px !important;
padding-left: 0px !important;
}
.el-col-6 {
padding-right: 0px !important;
padding-left: 0px !important;
}
.footer-table {
padding-top: 0px;
padding-right: 9px;
padding-bottom: 0px;
padding-left: 9px;
height: auto !important;
}
.keypad {
float: left;
height: 20%;
padding-top: 25px;
}
.total {
margin-top: 10px;
margin-bottom: 10px
}
.split {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
overflow-y: hidden;
overflow-x: hidden;
height: 100%;
width: 100%;
}
.el-card__body {
padding-top: 0px !important;
padding-right: 0px!important;
padding-bottom: 20px;
padding-left: 10px!important;
height: 100%!important;
}
/* Style of Table */
.el-table {
position: relative;
overflow: hidden;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
width: 100%;
max-width: 100%;
height: 100%;
background-color: #FFFFFF;
font-size: 14px;
color: #606266;
}
.el-card__header {
padding: 0px 20px;
border-bottom: 1px solid #e6ebf5;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.time {
font-size: 13px;
color: #999;
}
.bottom {
margin-top: 13px;
line-height: 12px;
}
.button {
padding: 0;
float: right;
}
.image {
width: 100%;
display: block;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
.el-header {
background: 'white';
color: #333;
line-height: 10px;
}
.el-aside {
color: #333;
}
.el-row {
margin: 0px!important;
}
.el-tag--medium {
height: 34px;
line-height: 32px;
}
.el-col {
border-radius: 4px;
}
.bg-purple-dark {
background: #99a9bf;
}
.bg-purple {
background: #d3dce6;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
.order-header {
padding-left: 10px;
font-size: 13px;
}
.order-info {
float: right;
padding-left: 9px;
}
</style>

View File

@ -0,0 +1,212 @@
import {
requestCreateOrderLine,
updateOrderLine,
requestDeleteOrderLine
} from '@/api/ADempiere/form/point-of-sales.js'
import { formatPercent } from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'OrderLineMixin',
data() {
return {
orderLineDefinition: {
lineDescription: {
columnName: 'LineDescription',
label: this.$t('form.pos.tableProduct.product'),
isNumeric: false
},
currentPrice: {
columnName: 'CurrentPrice',
label: this.$t('form.pos.product.price'),
isNumeric: true
},
quantityOrdered: {
columnName: 'QtyOrdered',
label: this.$t('form.pos.tableProduct.quantity'),
isNumeric: true
},
discount: {
columnName: 'Discount',
label: '% ' + this.$t('form.pos.order.discount'),
isNumeric: true
},
grandTotal: {
columnName: 'GrandTotal',
label: 'Total',
isNumeric: true
}
}
}
},
methods: {
formatPercent,
changeLine(command) {
switch (command) {
case 'Eliminar':
// this.deleteOrderLine()
break
//
case this.$t('form.pos.tableProduct.editQuantities'):
this.fillOrderLineQuantities({
currentPrice: this.currentOrderLine.currentPrice,
quantityOrdered: this.currentOrderLine.quantityOrdered,
discount: this.currentOrderLine.discount
})
this.edit = true
break
//
case 'informacion':
break
}
},
fillOrderLine(orderLine) {
this.$store.dispatch('updateOrderLines', orderLine)
},
createOrderLine(orderUuid) {
const productUuid = this.product.uuid
requestCreateOrderLine({
orderUuid,
productUuid
})
.then(orderLine => {
this.fillOrderLine(orderLine)
this.reloadOrder(true, orderUuid)
})
.catch(error => {
console.warn(error.message)
this.$message({
type: 'error',
message: error.message,
showClose: true
})
})
},
listOrderLines({ uuid: orderUuid }) {
if (!this.isEmptyValue(orderUuid)) {
this.$store.dispatch('listOrderLinesFromServer', orderUuid)
this.orderLines = this.listOrderLine
this.handleCurrentLineChange(this.currentOrderLine)
}
},
updateOrderLine(line) {
let {
currentPrice: price,
discount: discountRate,
quantityOrdered: quantity
} = this.currentOrderLine
switch (line.columnName) {
case 'QtyEntered':
quantity = line.value
break
case 'PriceEntered':
price = line.value
break
case 'Discount':
discountRate = line.value
break
}
updateOrderLine({
orderLineUuid: this.currentOrderLine.uuid,
quantity,
price,
discountRate
})
.then(response => {
this.fillOrderLine(response)
this.reloadOrder(true)
})
.catch(error => {
console.error(error.message)
this.$message({
type: 'error',
message: error.message,
showClose: true
})
})
},
deleteOrderLine(lineSelection) {
requestDeleteOrderLine({
orderLineUuid: lineSelection.uuid
})
.then(() => {
this.reloadOrder(true)
})
.catch(error => {
console.error(error.message)
this.$message({
type: 'error',
message: error.message,
showClose: true
})
})
},
/**
* Show the correct display format
* @param {object} row record
* @param {object} orderLine or field definition
*/
displayValue(row, orderLine) {
const { columnName } = orderLine
if (columnName === 'LineDescription') {
return row.lineDescription
}
const currency = this.currencyPoint.iSOCode
if (columnName === 'CurrentPrice') {
return this.formatPrice(row.priceActual, currency)
} else if (columnName === 'QtyOrdered') {
return this.formatQuantity(row.quantityOrdered)
} else if (columnName === 'Discount') {
return this.formatPercent(row.discount)
} else if (columnName === 'GrandTotal') {
return this.formatPrice(row.grandTotal, currency)
}
},
handleCurrentLineChange(rowLine) {
if (!this.isEmptyValue(rowLine)) {
this.currentOrderLine = rowLine
this.currentTable = this.listOrderLine.findIndex(item => item.uuid === rowLine.uuid)
if (this.isEmptyValue(this.currentOrderLine) && !this.isEmptyValue(this.listOrderLine)) {
this.$refs.linesTable.setCurrentRow(this.listOrderLine[this.currentTable])
}
}
},
fillOrderLineQuantities({
currentPrice,
quantityOrdered,
discount
}) {
const containerUuid = this.formUuid
// Editable fields
if (!this.isEmptyValue(quantityOrdered)) {
this.$store.commit('updateValueOfField', {
containerUuid,
columnName: 'QtyEntered',
value: quantityOrdered
})
}
if (!this.isEmptyValue(currentPrice)) {
this.$store.commit('updateValueOfField', {
containerUuid,
columnName: 'PriceEntered',
value: currentPrice
})
}
if (!this.isEmptyValue(discount)) {
this.$store.commit('updateValueOfField', {
containerUuid,
columnName: 'Discount',
value: discount
})
}
},
isValidForDeleteLine(line) {
if (this.isEmptyValue(this.currentOrderLine) && !this.isEmptyValue(this.orderLines)) {
this.currentOrderLine = this.orderLines[0]
}
return !this.isEmptyValue(line)
}
}
}

View File

@ -0,0 +1,105 @@
const tableName = 'C_Order'
export default [
{
tableName,
columnName: 'DocumentNo',
isFromDictionary: true,
overwriteDefinition: {
size: 8,
isMandatory: false
}
},
{
tableName,
columnName: 'C_BPartner_ID',
isFromDictionary: true,
overwriteDefinition: {
size: 8,
isMandatory: false
}
},
{
tableName,
columnName: 'GrandTotal',
isFromDictionary: true,
overwriteDefinition: {
size: 8,
isMandatory: false
}
},
{
tableName,
elementColumnName: 'OpenAmt',
isFromDictionary: true,
overwriteDefinition: {
size: 8,
isMandatory: false
}
},
{
tableName,
elementColumnName: 'IsPaid',
isFromDictionary: true,
overwriteDefinition: {
size: 8,
isMandatory: false
}
},
{
tableName,
columnName: 'Processed',
isFromDictionary: true,
overwriteDefinition: {
size: 8,
isMandatory: false
}
},
{
tableName,
elementColumnName: 'IsAisleSeller',
isFromDictionary: true,
overwriteDefinition: {
size: 8,
isMandatory: false
}
},
{
tableName,
columnName: 'IsInvoiced',
isFromDictionary: true,
overwriteDefinition: {
size: 8,
isMandatory: false
}
},
{
tableName,
columnName: 'DateOrdered',
isFromDictionary: true,
overwriteDefinition: {
columnName: 'DateOrderedFrom',
size: 8,
isMandatory: false
}
},
{
tableName,
columnName: 'DateOrdered',
isFromDictionary: true,
overwriteDefinition: {
columnName: 'DateOrderedTo',
size: 8,
isMandatory: false
}
},
{
tableName,
columnName: 'SalesRep_ID',
isFromDictionary: true,
overwriteDefinition: {
size: 8,
isMandatory: false
}
}
]

View File

@ -0,0 +1,318 @@
<template>
<el-main
v-shortkey="shortsKey"
@shortkey.native="keyAction"
>
<el-collapse v-model="activeAccordion" accordion>
<el-collapse-item name="query-criteria">
<template slot="title">
Ver Histórico de Órdenes
</template>
<el-form
v-if="isLoaded"
label-position="top"
label-width="10px"
@submit.native.prevent="notSubmitForm"
>
<template
v-for="(field) in fieldsList"
>
<field-definition
:key="field.columnName"
:metadata-field="field"
/>
</template>
</el-form>
<div
v-else
key="form-loading"
v-loading="!isLoaded"
:element-loading-text="$t('notifications.loading')"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(255, 255, 255, 0.8)"
class="loading-panel"
/>
</el-collapse-item>
</el-collapse>
<el-table
ref="orderTable"
v-shortkey="shortsKey"
v-loading="!tableOrder.isLoaded"
:data="ordersList"
border
fit
:highlight-current-row="highlightRow"
:height="heightTable"
@shortkey.native="keyAction"
@current-change="handleCurrentChange"
>
<el-table-column
prop="documentNo"
label="Nro. Documento"
width="130"
/>
<el-table-column
label="Estado"
width="100"
>
<template slot-scope="scope">
<el-tag
:type="tagStatus(scope.row.documentStatus.value)"
>
{{ scope.row.documentStatus.name }}
</el-tag>
</template>
</el-table-column>
<el-table-column
prop="salesRepresentative.name"
label="Agente Comercial"
min-width="170"
/>
<el-table-column
label="Socio de Negocio"
min-width="150"
>
<template slot-scope="scope">
{{ scope.row.businessPartner.name }}
</template>
</el-table-column>
<el-table-column
label="Fecha de Orden"
width="135"
>
<template slot-scope="scope">
{{ formatDate(scope.row.dateOrdered) }}
</template>
</el-table-column>
<el-table-column
label="Total General"
align="right"
width="120"
>
<template slot-scope="scope">
{{ formatQuantity(scope.row.grandTotal) }}
</template>
</el-table-column>
</el-table>
<custom-pagination
:total="tableOrder.recordCount"
:current-page="tableOrder.pageNumber"
:handle-change-page="handleChangePage"
/>
</el-main>
</template>
<script>
import formMixin from '@/components/ADempiere/Form/formMixin.js'
import CustomPagination from '@/components/ADempiere/Pagination'
import fieldsListOrders from './fieldsListOrders.js'
import {
formatDate,
formatQuantity
} from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'OrdersList',
components: {
CustomPagination
},
mixins: [
formMixin
],
props: {
metadata: {
type: Object,
default: () => {
return {
uuid: 'Orders-List',
containerUuid: 'Orders-List'
}
}
}
},
data() {
return {
defaultMaxPagination: 50,
fieldsList: fieldsListOrders,
isCustomForm: true,
activeAccordion: 'query-criteria',
timeOut: null
}
},
computed: {
heightTable() {
if (this.isEmptyValue(this.activeAccordion)) {
return 500
}
return 250
},
highlightRow() {
if (!this.isEmptyValue(this.selectOrder)) {
return true
}
return false
},
tableOrder() {
return this.$store.getters.getListOrder
},
ordersList() {
const order = this.tableOrder
if (order && !this.isEmptyValue(order.ordersList)) {
return order.ordersList
}
return []
},
selectOrder() {
const action = this.$route.query.action
const order = this.ordersList.find(item => item.uuid === action)
if (!this.isEmptyValue(order)) {
return order
}
this.$store.dispatch('listOrderLine', [])
return null
},
isReadyFromGetData() {
const { isLoaded, isReload } = this.tableOrder
return !isLoaded || isReload
},
shortsKey() {
return {
closeOrdersList: ['esc'],
refreshList: ['f5']
}
}
},
watch: {
isReadyFromGetData(isToLoad) {
if (isToLoad) {
this.loadOrdersList()
}
}
},
created() {
this.unsubscribe = this.subscribeChanges()
if (this.isReadyFromGetData) {
this.loadOrdersList()
}
},
beforeDestroy() {
this.unsubscribe()
},
methods: {
formatDate,
formatQuantity,
keyAction(event) {
switch (event.srcKey) {
case 'refreshList':
this.loadOrdersList()
break
case 'closeOrdersList':
this.$store.commit('showListOrders', false)
break
}
},
loadOrdersList() {
let values = this.$store.getters.getValuesView({
containerUuid: this.metadata.containerUuid
})
values = this.convertValuesToSend(values)
this.$store.dispatch('listOrdersFromServer', {
...values
})
},
handleChangePage(newPage) {
this.$store.dispatch('setOrdersListPageNumber', newPage)
},
handleCurrentChange(row) {
// close popover
this.$store.commit('showListOrders', false)
this.$store.dispatch('currentOrder', row)
if (!this.isEmptyValue(row)) {
this.$store.dispatch('deleteAllCollectBox')
this.$router.push({
params: {
...this.$route.params
},
query: {
...this.$route.query,
action: row.uuid
}
}, () => {})
}
},
subscribeChanges() {
return this.$store.subscribe((mutation, state) => {
if (mutation.type === 'updateValueOfField' &&
!mutation.payload.columnName.includes('DisplayColumn') &&
!mutation.payload.columnName.includes('_UUID') &&
mutation.payload.containerUuid === this.metadata.containerUuid) {
clearTimeout(this.timeOut)
this.timeOut = setTimeout(() => {
this.loadOrdersList()
}, 2000)
}
})
},
convertValuesToSend(values) {
const valuesToSend = {}
values.forEach(element => {
const { value, columnName } = element
if (this.isEmptyValue(value)) {
return
}
switch (columnName) {
case 'DocumentNo':
valuesToSend['documentNo'] = value
break
case 'C_BPartner_ID_UUID':
valuesToSend['businessPartnerUuid'] = value
break
case 'GrandTotal':
valuesToSend['grandTotal'] = value
break
case 'OpenAmt':
valuesToSend['openAmount'] = value
break
case 'IsPaid':
valuesToSend['isPaid'] = value
break
case 'Processed':
valuesToSend['isProcessed'] = value
break
case 'IsAisleSeller':
valuesToSend['isAisleSeller'] = value
break
case 'IsInvoiced':
valuesToSend['isInvoiced'] = value
break
case 'DateOrderedFrom':
valuesToSend['dateOrderedFrom'] = value
break
case 'DateOrderedTo':
valuesToSend['dateOrderedTo'] = value
break
case 'SalesRep_ID_UUID':
valuesToSend['salesRepresentativeUuid'] = value
break
}
})
return valuesToSend
}
}
}
</script>

View File

@ -0,0 +1,12 @@
export default [
// Product Code
{
elementColumnName: 'ProductValue',
columnName: 'ProductValue',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
sequence: 10
}
}
]

View File

@ -0,0 +1,254 @@
<template>
<div>
<el-popover
ref="productsList"
v-model="isShowProductsPriceList"
placement="right"
width="800"
trigger="manual"
>
<product-info-list
v-if="isShowProductsPriceList"
/>
</el-popover>
<el-form-item>
<template slot="label">
Código Producto
<!-- Ver Lista de Productos Y Precios -->
<el-button
v-popover:productsList
type="text"
icon="el-icon-search"
style="color: black"
@click="isShowProductsPriceList = !isShowProductsPriceList"
/>
</template>
<el-autocomplete
v-model="value"
v-shortkey="keyShortcuts"
:placeholder="$t('quickAccess.searchWithEnter')"
clearable
style="width: 100%;"
popper-class="custom-field-prodcut-info"
:fetch-suggestions="localSearch"
@shortkey.native="shortcutKeyMethod"
@select="handleSelect"
>
<template slot="prefix">
<svg-icon
icon-class="shopping"
class="el-input__icon"
/>
<!--
<i
class="el-icon-shopping-cart-full el-input__icon"
/>
-->
</template>
<template slot-scope="props">
<div class="header">
<b> {{ props.item.product.value }} - {{ props.item.product.name }} </b>
</div>
<el-row :gutter="20">
<el-col :span="12">
<span class="upc">
<!-- <b>UPC / EAN Barras:</b> <br> -->
{{ props.item.product.upc }} <br>
<span class="description">
{{ props.item.product.description }}
</span>
</span>
</el-col>
<!-- <el-col :span="6">
<span class="upc">
{{ props.item.product.description }}
</span>
</el-col> -->
<!-- <el-col :span="6">
<span class="upc">
{{ props.item.quantityAvailable }}
</span>
</el-col> -->
<el-col :span="12">
<span class="price">
{{ formatPrice(props.item.priceStandard, props.item.currency.iSOCode) }}
<br>
<span class="quantityAvailable">
{{ formatQuantity(props.item.quantityAvailable) }}
</span>
<!-- {{ props.item.currency.curSymbol }} -->
</span>
</el-col>
</el-row>
</template>
</el-autocomplete>
</el-form-item>
</div>
</template>
<script>
/**
* This component is made to be the prototype of the Product Info search field
*/
import ProductInfoList from './productList'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import {
formatPrice,
formatQuantity
} from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'FieldProductInfo',
components: {
ProductInfoList
},
mixins: [
fieldMixin
],
data() {
return {
timeOut: null
}
},
computed: {
isShowProductsPriceList: {
get() {
return this.$store.state['pointOfSales/listProductPrice'].productPrice.isShowPopoverField
},
set(isShowed) {
if (!this.isEmptyValue(this.$route.query.pos)) {
this.$store.commit('showListProductPrice', {
attribute: 'isShowPopoverField',
isShowed
})
}
}
},
listWithPrice() {
const { productPricesList } = this.$store.getters.getProductPrice
if (!this.isEmptyValue(productPricesList)) {
return productPricesList
}
return []
},
keyShortcuts() {
return {
refreshList: ['f5'],
refreshList2: ['shift', 'f5']
}
}
},
methods: {
formatPrice,
formatQuantity,
shortcutKeyMethod(event) {
switch (event.srcKey) {
case 'refreshList':
case 'refreshList2':
this.$store.dispatch('listProductPriceFromServer', {})
break
}
},
localSearch(stringToMatch, callBack) {
if (this.isEmptyValue(stringToMatch)) {
// not show list
callBack([])
return
}
let results = this.listWithPrice
if (stringToMatch) {
const parsedValue = stringToMatch.toLowerCase().trim()
results = results.filter(rowProduct => {
const productAttributes = rowProduct.product
for (const columnProductPrice in productAttributes) {
const valueToCompare = String(productAttributes[columnProductPrice]).toLowerCase()
if (valueToCompare.includes(parsedValue)) {
return true
}
}
return false
})
// Remote search
if (this.isEmptyValue(results) && String(stringToMatch.length > 3)) {
clearTimeout(this.timeOut)
this.timeOut = setTimeout(() => {
this.$store.dispatch('listProductPriceFromServer', {
pageNumber: 1,
searchValue: stringToMatch
})
.then(() => {
const recordsList = this.listWithPrice
if (this.isEmptyValue(recordsList)) {
this.$message({
message: 'Sin resultados coincidentes con la busqueda',
type: 'info',
showClose: true
})
}
callBack(recordsList)
})
}, 2000)
return
}
}
// call callback function to return suggestions
callBack(results)
},
handleSelect(elementSelected) {
const valueProduct = elementSelected.product.value
this.$store.dispatch('notifyActionKeyPerformed', {
containerUuid: 'POS',
columnName: 'ProductValue',
// TODO: Verify with 'value' or 'searchValue' attribute
value: valueProduct
})
}
}
}
</script>
<style lang="scss" scope>
.custom-field-prodcut-info {
li {
line-height: normal;
padding: 15px;
.header {
text-overflow: ellipsis;
overflow: hidden;
}
.upc {
color: #7e7e7e;
padding-top: 10px;
float: left;
}
.description {
padding-top: 10px;
float: left;
}
.price {
color: #7e7e7e;
padding-top: 10px;
float: right;
padding-right: 10px;
}
.quantityAvailable {
float: right;
padding-top: 10px;
}
}
}
</style>

View File

@ -0,0 +1,208 @@
<template>
<el-main
v-shortkey="shortsKey"
@shortkey.native="keyAction"
>
<el-form
v-shortkey="shortsKey"
label-position="top"
label-width="10px"
@shortkey.native="keyAction"
@submit.native.prevent="notSubmitForm"
>
<field-definition
v-for="(field) in fieldsList"
:key="field.columnName"
:metadata-field="field"
/>
</el-form>
<el-table
ref="listProducto"
v-shortkey="shortsKey"
v-loading="!productPrice.isLoaded"
:data="listWithPrice"
border
fit
height="450"
highlight-current-row
@row-click="findlistProductWithRow"
@shortkey.native="keyAction"
>
<el-table-column
prop="product.value"
label="Codigo"
/>
<el-table-column
prop="product.name"
label="Producto"
/>
<el-table-column
prop="priceListName"
label="Lista de Precio"
/>
<el-table-column
label="Precio"
align="right"
>
<template slot-scope="scope">
{{ formatPrice(scope.row.priceStandard) }}
</template>
</el-table-column>
</el-table>
<custom-pagination
:total="productPrice.recordCount"
:current-page="productPrice.pageNumber"
:handle-change-page="handleChangePage"
/>
</el-main>
</template>
<script>
import formMixin from '@/components/ADempiere/Form/formMixin.js'
import CustomPagination from '@/components/ADempiere/Pagination'
import fieldsListProductPrice from './fieldsList.js'
import { formatPrice } from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'ProductList',
components: {
CustomPagination
},
mixins: [
formMixin
],
props: {
metadata: {
type: Object,
default: () => {
return {
uuid: 'Products-Price-List',
containerUuid: 'Products-Price-List'
}
}
},
isSelectable: {
type: Boolean,
default: true
},
popoverName: {
type: String,
default: 'isShowPopoverField'
}
},
data() {
return {
defaultMaxPagination: 50,
fieldsList: fieldsListProductPrice,
isCustomForm: true,
timeOut: null
}
},
computed: {
isShowProductsPriceList() {
return this.$store.state['pointOfSales/listProductPrice'].productPrice[this.attribute]
},
currentPoint() {
return this.$store.getters.getCurrentPOS
},
productPrice() {
return this.$store.getters.getProductPrice
},
listWithPrice() {
const { productPricesList } = this.productPrice
if (!this.isEmptyValue(productPricesList)) {
return productPricesList
}
return []
},
shortsKey() {
return {
closeProductList: ['esc'],
refreshList: ['f5']
}
},
isReadyFromGetData() {
const { isLoaded, isReload } = this.productPrice
return (!isLoaded || isReload) // && this.isShowProductsPriceList
}
},
watch: {
isReadyFromGetData(isToLoad) {
if (isToLoad) {
this.loadProductsPricesList()
}
}
},
created() {
this.unsubscribe = this.subscribeChanges()
if (this.isReadyFromGetData) {
this.loadProductsPricesList()
}
},
beforeDestroy() {
this.unsubscribe()
},
methods: {
formatPrice,
keyAction(event) {
switch (event.srcKey) {
case 'refreshList':
/**
* TODO: When refreshing you are making 2 list requests, you can be the
* observer that activates the second request
*/
this.loadProductsPricesList()
break
case 'closeProductList':
this.$store.commit('showListProductPrice', {
attribute: this.popoverName,
isShowed: false
})
break
}
},
loadProductsPricesList() {
this.$store.dispatch('listProductPriceFromServer', {})
},
/**
* @param {number} newPage
*/
handleChangePage(newPage) {
this.$store.dispatch('setProductPicePageNumber', newPage)
},
findlistProductWithRow(row) {
if (!this.isSelectable) {
return
}
// TODO: Change this dispatch for set values with local methods, to delete subscripton
this.$store.dispatch('notifyActionKeyPerformed', {
containerUuid: 'POS',
columnName: 'ProductValue',
// TODO: Verify with 'value' or 'searchValue' attribute
value: row.product.name
})
// close popover of list product price
this.$store.commit('showListProductPrice', {
attribute: this.popoverName,
isShowed: false
})
},
subscribeChanges() {
return this.$store.subscribe((mutation, state) => {
if (mutation.type === 'updateValueOfField' &&
!mutation.payload.columnName.includes('DisplayColumn') &&
mutation.payload.containerUuid === this.metadata.containerUuid) {
clearTimeout(this.timeOut)
this.timeOut = setTimeout(() => {
this.$store.commit('setIsReloadProductPrice')
}, 1000)
}
})
}
}
}
</script>

View File

@ -0,0 +1,271 @@
<template>
<el-container style="height: 100% !important;">
<el-main style="padding-right: 0px;padding-bottom: 0px;">
<Split :gutter-size="isShowedPOSOptions ? 10 : 0" @onDrag="onDragOption">
<SplitArea :size="isShowedPOSOptions ? 20 : 1" :min-size="400">
<el-container style="height: 100% !important;">
<el-aside :width="isShowedPOSOptions ? '100%' : '0%'" style="background: white; padding: 0px !important; margin-bottom: 0px">
<options
:metadata="metadata"
/>
</el-aside>
<div style="width: 36px;padding-top: 30vh; z-index: 100;">
<el-button
:circle="true"
type="primary"
:icon="isShowedPOSOptions ? 'el-icon-arrow-left' : 'el-icon-arrow-right'"
:style="isShowedPOSOptions ? 'position: absolute;': 'position: absolute;left: 0.8%;'"
@click="isShowedPOSOptions = !isShowedPOSOptions"
/>
</div>
</el-container>
</SplitArea>
<SplitArea :size="isShowedPOSOptions ? 80 : 99" :min-size="990">
<Split :gutter-size="isShowedPOSKeyLaout ? 10 : 0" @onDrag="onDragKeyLayout">
<SplitArea :size="isShowedPOSKeyLaout ? 69 : 99" :min-size="900" style="overflow: hidden">
<order
:metadata="metadata"
/>
</SplitArea>
<SplitArea
v-show="isShowedPOSKeyLaout"
:size="isShowedPOSKeyLaout ? 31: 1"
:min-size="300"
style="overflow: auto"
>
<key-layout
v-if="!showCollection"
key="layout-component"
/>
<collection
v-else
key="collection-component"
/>
</SplitArea>
</Split>
</SplitArea>
</Split>
</el-main>
</el-container>
</template>
<script>
import Order from '@/components/ADempiere/Form/VPOS/Order'
import KeyLayout from '@/components/ADempiere/Form/VPOS/KeyLayout'
import Options from '@/components/ADempiere/Form/VPOS/Options'
import Collection from '@/components/ADempiere/Form/VPOS/Collection'
export default {
name: 'VPOS',
components: {
Order,
KeyLayout,
Options,
Collection
},
props: {
metadata: {
type: Object,
required: true
}
},
data() {
return {
unsubscribePOSList: () => {}
}
},
computed: {
// options to POS, panel left
isShowedPOSOptions: {
get() {
return this.$store.getters.getIsShowPOSOptions
},
set(val) {
this.$store.commit('setShowPOSOptions', val)
}
},
isShowedPOSKeyLaout() {
return this.$store.getters.getShowPOSKeyLayout
},
showCollection() {
return this.$store.getters.getShowCollectionPos
},
pointOfSalesId() {
const currentPOS = this.$store.getters.getCurrentPOS
if (currentPOS && !this.isEmptyValue(currentPOS.id)) {
return currentPOS.id
}
return undefined
}
},
watch: {
isShowedPOSOptions(value) {
if (value) {
if (this.isShowedPOSKeyLaout) {
this.$store.dispatch('changeWidthRight', 3)
}
} else {
this.$store.dispatch('changeWidthRight', 3)
}
}
},
created() {
// load pont of sales list
if (this.isEmptyValue(this.$store.getters.getSellingPointsList)) {
let posToSet
// set pos id with query path
if (!this.isEmptyValue(this.$route.query) && !this.isEmptyValue(this.$route.query.pos)) {
posToSet = Number(this.$route.query.pos)
}
this.$store.dispatch('listPointOfSalesFromServer', posToSet)
}
this.unsubscribePOSList = this.posListWithOrganization()
if (!this.isEmptyValue(this.$route.query.action)) {
this.$store.dispatch('findOrderServer', this.$route.query.action)
}
},
mounted() {
if (this.isEmptyValue(this.$route.query) || this.isEmptyValue(this.$route.query.pos)) {
this.$router.push({
params: {
...this.$route.params
},
query: {
...this.$route.query,
pos: this.pointOfSalesId
}
}, () => {})
}
},
beforeDestroy() {
this.unsubscribePOSList()
},
methods: {
posListWithOrganization() {
return this.$store.subscribe((mutation, state) => {
if (mutation.type === 'user/SET_ORGANIZATION') {
this.$store.dispatch('listPointOfSalesFromServer')
}
})
},
onDragKeyLayout(size) {
const sizeWidthRight = size[1] / 10
this.$store.dispatch('changeWidthRight', Math.trunc(sizeWidthRight))
},
onDragOption(size) {
const sizeWidthLeft = size[0] / 10
this.$store.dispatch('changeWidthLeft', Math.trunc(sizeWidthLeft))
}
}
}
</script>
<style scoped>
.split {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
overflow-y: hidden;
overflow-x: hidden;
height: 100%;
width: 100%;
}
.el-card__body {
padding-top: 0px !important;
padding-right: 0px!important;
padding-bottom: 20px;
padding-left: 10px!important;
height: 100%!important;
}
/* Style of Table */
.el-table {
position: relative;
overflow: hidden;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
width: 100%;
max-width: 100%;
height: 100%;
background-color: #FFFFFF;
font-size: 14px;
color: #606266;
}
.el-card__header {
padding: 0px 20px;
border-bottom: 1px solid #e6ebf5;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.time {
font-size: 13px;
color: #999;
}
.bottom {
margin-top: 13px;
line-height: 12px;
}
.button {
padding: 0;
float: right;
}
.image {
width: 100%;
display: block;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
.el-header {
background: 'white';
color: #333;
line-height: 10px;
}
.el-aside {
color: #333;
}
.el-row {
margin: 0px!important;
}
.el-col {
border-radius: 4px;
}
.bg-purple-dark {
background: #99a9bf;
}
.bg-purple {
background: #d3dce6;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
.order-header {
padding-left: 10px;
font-size: 13px;
}
</style>

View File

@ -0,0 +1,444 @@
import {
findProduct,
requestCreateOrder,
requestGetOrder,
requestUpdateOrder
} from '@/api/ADempiere/form/point-of-sales.js'
import {
formatDate,
formatPrice,
formatQuantity
} from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'POSMixin',
props: {
metadata: {
type: Object,
required: false
}
},
data() {
return {
product: {},
order: {
documentType: {},
documentStatus: {
value: ''
},
totalLines: 0,
grandTotal: 0,
salesRepresentative: {},
businessPartner: {
value: ''
}
},
currentTable: 0,
currentOrderLine: {
product: {
value: 0,
name: '',
description: '',
priceStandard: 0
},
taxIndicator: 0,
quantityOrdered: 0
},
orderLines: [],
products: {
uuid: '',
quantityAvailable: 0
},
edit: false,
displayType: ''
}
},
computed: {
allOrderLines() {
if (this.isEmptyValue(this.listOrderLine)) {
return []
}
return this.listOrderLine
},
listOrderLine() {
return this.$store.getters.getListOrderLine
},
ordersList() {
const order = this.$store.getters.getListOrder
if (order && !this.isEmptyValue(order.ordersList)) {
return order.ordersList
}
return []
},
currentOrder() {
const action = this.$route.query.action
if (!this.isEmptyValue(action)) {
const order = this.ordersList.find(item => item.uuid === action)
if (!this.isEmptyValue(order)) {
return order
}
}
return this.$store.getters.getFindOrder
},
currentPoint() {
return this.$store.getters.getCurrentPOS
},
priceListUuid() {
const currentPOS = this.currentPoint
if (this.isEmptyValue(currentPOS)) {
return undefined
}
return this.currentPoint.priceList.uuid
},
getWarehouse() {
return this.$store.getters['user/getWarehouse']
},
isSetTemplateBP() {
const currentPOS = this.currentPoint
if (!this.isEmptyValue(currentPOS) &&
!this.isEmptyValue(currentPOS.templateBusinessPartner) &&
this.isEmptyValue(this.$route.query.action)) {
return currentPOS.templateBusinessPartner
}
return false
}
},
watch: {
currentOrder(value) {
if (this.isEmptyValue(value)) {
this.orderLines = []
this.order = {
documentType: {},
documentStatus: {},
salesRepresentative: {}
}
this.$store.dispatch('listOrderLine', [])
this.listOrderLines({})
} else {
this.fillOrder(value)
this.listOrderLines(value)
}
},
/**
* Used when loading/reloading the app without the order uuid
* @param {oject|boolean} bPartnerToSet
*/
isSetTemplateBP(bPartnerToSet) {
if (bPartnerToSet) {
this.setBusinessPartner(bPartnerToSet)
}
}
},
created() {
this.getPanel()
},
beforeMount() {
if (!this.isEmptyValue(this.currentPoint)) {
if (!this.isEmptyValue(this.currentOrder)) {
this.fillOrder(this.currentOrder)
this.listOrderLines(this.currentOrder)
}
}
this.unsubscribe = this.subscribeChanges()
},
beforeDestroy() {
this.unsubscribe()
},
methods: {
formatDate,
formatPrice,
formatQuantity,
withoutPOSTerminal() {
if (this.isEmptyValue(this.currentPoint)) {
this.$message({
type: 'warn',
message: 'Without POS Terminal',
showClose: true
})
return true
}
return false
},
arrowTop() {
if (this.currentTable > 0) {
this.currentTable--
this.$refs.linesTable.setCurrentRow(this.listOrderLine[this.currentTable])
this.currentOrderLine = this.listOrderLine[this.currentTable]
}
},
arrowBottom() {
const top = this.listOrderLine.length - 1
if (this.currentTable < top) {
this.currentTable++
this.$refs.linesTable.setCurrentRow(this.listOrderLine[this.currentTable])
this.currentOrderLine = this.listOrderLine[this.currentTable]
}
},
updateOrder(update) {
if (this.withoutPOSTerminal()) {
return
}
if (!this.$route.query || this.isEmptyValue(this.$route.query.action)) {
return
}
const { uuid: posUuid } = this.currentPoint
let customerUuid
if (update.columnName === 'C_BPartner_ID_UUID') {
customerUuid = update.value
if (this.isEmptyValue(customerUuid)) {
customerUuid = this.currentPoint.templateBusinessPartner.uuid
}
}
requestUpdateOrder({
orderUuid: this.$route.query.action,
posUuid,
customerUuid
// documentTypeUuid: value.value,
// description
})
.then(response => {
// this.reloadOrder(true)
})
.catch(error => {
console.error(error.message)
this.$message({
type: 'error',
message: error.message,
showClose: true
})
})
},
setBusinessPartner({ name, id, uuid }) {
// Use update values of container (without subscription)
this.$store.commit('updateValuesOfContainer', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
attributes: [{
columnName: 'C_BPartner_ID',
value: id
},
{
columnName: 'DisplayColumn_C_BPartner_ID',
value: name
},
{
columnName: ' C_BPartner_ID_UUID',
value: uuid
}]
})
},
findProduct(searchValue) {
if (this.withoutPOSTerminal()) {
return
}
const searchProduct = (typeof searchValue === 'object') ? searchValue.value : searchValue
findProduct({
searchValue: searchProduct,
priceListUuid: this.priceListUuid
})
.then(productPrice => {
this.product = productPrice.product
this.createOrder(true)
})
.catch(error => {
console.warn(error.message)
this.$message({
type: 'info',
message: error.message,
showClose: true
})
this.$store.commit('updateValueOfField', {
containerUuid: 'Products-Price-List',
columnName: 'ProductValue',
value: `${searchProduct}`
})
this.$store.commit('showListProductPrice', {
attribute: 'isShowPopoverField',
isShowed: true
})
})
.finally(() => {
this.$store.commit('updateValuesOfContainer', {
containerUuid: this.metadata.containerUuid,
attributes: [{
columnName: 'ProductValue',
value: undefined
}]
})
})
},
createOrder(withLine) {
if (this.withoutPOSTerminal()) {
return
}
const orderUuid = this.$route.query.action
if (this.isEmptyValue(orderUuid)) {
const posUuid = this.currentPoint.uuid
let customerUuid = this.$store.getters.getValueOfField({
containerUuid: this.containerUuid,
columnName: 'C_BPartner_ID_UUID'
})
if (this.isEmptyValue(customerUuid)) {
customerUuid = this.currentPoint.templateBusinessPartner.uuid
}
// user session
const salesRepresentativeUuid = this.$store.getters['user/getUserUuid']
requestCreateOrder({
posUuid,
customerUuid,
salesRepresentativeUuid
})
.then(order => {
this.$store.dispatch('currentOrder', order)
this.fillOrder(order)
this.$router.push({
params: {
...this.$route.params
},
query: {
...this.$route.query,
action: order.uuid
}
}).then(() => {
if (withLine) {
this.createOrderLine(order.uuid)
}
}).catch(() => {})
// update orders list
this.$store.commit('setIsReloadListOrders')
})
.catch(error => {
console.error(error.message)
this.$message({
type: 'error',
message: error.message,
showClose: true
})
})
} else {
this.createOrderLine(orderUuid)
}
},
reloadOrder(requery, orderUuid) {
if (requery) {
if (this.isEmptyValue(orderUuid)) {
orderUuid = this.$route.query.action
if (this.isEmptyValue(orderUuid)) {
orderUuid = this.$store.getters.getOrder.uuid // this.currentOrder.uuid
}
}
if (!this.isEmptyValue(orderUuid)) {
requestGetOrder(orderUuid)
.then(orderResponse => {
this.fillOrder(orderResponse)
this.$store.dispatch('currentOrder', orderResponse)
this.listOrderLines(orderResponse)
})
.catch(error => {
this.$message({
type: 'error',
message: error.message,
showClose: true
})
})
}
} else {
this.fillOrder(this.currentOrder, false)
}
},
fillOrder(order, setToStore = true) {
const orderToPush = {
uuid: order.uuid,
id: order.id,
businessPartner: order.businessPartner, // description, duns, id, lastName, naics, name, taxId, uuid, value
documentNo: order.documentNo,
dateOrdered: order.dateOrdered,
documentStatus: order.documentStatus, // value, name, description
documentType: order.documentType, // name, printName
salesRepresentative: order.salesRepresentative, // id, uuid, name, description,
totalLines: order.totalLines,
grandTotal: order.grandTotal
}
if (setToStore) {
this.$store.dispatch('setOrder', {
...orderToPush
})
}
if (!this.isEmptyValue(order.businessPartner)) {
const { businessPartner } = order
this.setBusinessPartner(businessPartner)
}
this.order = orderToPush
},
getOrderTax(currency) {
if (this.isEmptyValue(this.order)) {
return undefined
}
return this.formatPrice(this.order.grandTotal - this.order.totalLines, currency)
},
subscribeChanges() {
return this.$store.subscribe((mutation, state) => {
// TODO: Add container uuid comparison
if (mutation.type === 'addActionKeyPerformed') {
switch (mutation.payload.columnName) {
case 'ProductValue':
this.findProduct(mutation.payload.value)
break
}
} else if (mutation.type === 'addActionPerformed') {
switch (mutation.payload.columnName) {
case 'QtyEntered':
case 'PriceEntered':
case 'Discount':
if (!this.isEmptyValue(this.currentOrderLine)) {
this.updateOrderLine(mutation.payload)
}
break
//
case 'C_DocType_ID':
this.updateOrder(mutation.payload)
break
}
} else if (mutation.type === 'updateValueOfField') {
// if (this.metadata.containerUuid === mutation.payload.containerUuid &&
// mutation.payload.columnName === 'ProductValue') {
// this.findProduct(mutation.payload.value)
// }
switch (mutation.payload.columnName) {
case 'DisplayColumn_TenderType':
this.displayType = mutation.payload.value
break
case 'C_BPartner_ID_UUID': {
const bPartnerValue = mutation.payload.value
const bPartnerPOS = this.currentPoint.templateBusinessPartner.uuid
// Does not send values to server, when empty values are set or
// if BPartner set equal to BPartner POS template
if (this.isEmptyValue(bPartnerValue) || bPartnerValue === bPartnerPOS) {
break
}
this.updateOrder(mutation.payload)
break
}
}
}
})
}
}
}

View File

@ -55,7 +55,7 @@ export default {
async getPanel() { async getPanel() {
const panel = this.getterPanel const panel = this.getterPanel
if (!this.isEmptyValue(panel)) { if (!this.isEmptyValue(panel)) {
this.fieldsList = panel.fieldList this.fieldsList = panel.fieldsList
this.isLoaded = true this.isLoaded = true
this.panelMetadata = panel this.panelMetadata = panel
} else { } else {
@ -65,14 +65,14 @@ export default {
isCustomForm: this.isCustomForm, isCustomForm: this.isCustomForm,
uuid: this.containerUuid, uuid: this.containerUuid,
panelType: this.panelType, panelType: this.panelType,
fieldList: this.fieldsList fieldsList: this.fieldsList
}) })
.then(responsePanel => { .then(responsePanel => {
this.fieldsList = responsePanel.fieldList this.fieldsList = responsePanel.fieldsList
this.$store.dispatch('changeFormAttribute', { this.$store.dispatch('changeFormAttribute', {
containerUuid: this.containerUuid, containerUuid: this.containerUuid,
attributeName: 'fieldList', attributeName: 'fieldsList',
attributeValue: this.fieldsList attributeValue: this.fieldsList
}) })
this.panelMetadata = responsePanel this.panelMetadata = responsePanel

View File

@ -22,6 +22,9 @@ export default {
case 'PriceChecking': case 'PriceChecking':
form = import('@/components/ADempiere/Form/PriceChecking') form = import('@/components/ADempiere/Form/PriceChecking')
break break
case 'VPOS':
form = import('@/components/ADempiere/Form/VPOS')
break
default: default:
form = import('@/views/ADempiere/Unsupported') form = import('@/views/ADempiere/Unsupported')
break break

View File

@ -2,9 +2,9 @@
<el-footer style="height: 30px;"> <el-footer style="height: 30px;">
<div style="float: right;"> <div style="float: right;">
<el-pagination <el-pagination
:current-page="currentPage"
small small
layout="slot, total, prev, pager, next" layout="slot, total, prev, pager, next"
:current-page="currentPage"
:page-size="pageSize" :page-size="pageSize"
:total="total" :total="total"
@current-change="handleChangePage" @current-change="handleChangePage"

View File

@ -10,7 +10,7 @@
@change="addField" @change="addField"
> >
<el-option <el-option
v-for="(item, key) in getterFieldListOptional" v-for="(item, key) in fieldsListOptional"
:key="key" :key="key"
:label="item.name" :label="item.name"
:value="item.columnName" :value="item.columnName"
@ -48,7 +48,7 @@ export default {
isMobile() { isMobile() {
return this.$store.state.app.device === 'mobile' return this.$store.state.app.device === 'mobile'
}, },
getterFieldListOptional() { fieldsListOptional() {
if (this.panelType === 'table') { if (this.panelType === 'table') {
// fields to search without taking into account the mandatory // fields to search without taking into account the mandatory
return this.$store.getters.getFieldsListFromPanel(this.containerUuid, this.isAdvancedQuery) return this.$store.getters.getFieldsListFromPanel(this.containerUuid, this.isAdvancedQuery)
@ -66,7 +66,7 @@ export default {
return this.$store.getters.getFieldsListNotMandatory({ containerUuid: this.containerUuid }) return this.$store.getters.getFieldsListNotMandatory({ containerUuid: this.containerUuid })
}, },
getFieldSelected() { getFieldSelected() {
return this.getterFieldListOptional return this.fieldsListOptional
.filter(fieldItem => { .filter(fieldItem => {
return fieldItem.isShowedFromUser return fieldItem.isShowedFromUser
}) })

Some files were not shown because too many files have changed in this diff Show More