856 lines
32 KiB
Vue
856 lines
32 KiB
Vue
<script setup>
|
|
import { ref, onMounted, onUnmounted, watch, computed } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
import axios from 'axios';
|
|
import { date } from 'quasar';
|
|
import { useStateStore } from 'stores/useStateStore';
|
|
import { toRelativeDate } from 'src/filters';
|
|
import { useColor } from 'src/composables/useColor';
|
|
import { useCapitalize } from 'src/composables/useCapitalize';
|
|
import { useValidator } from 'src/composables/useValidator';
|
|
import VnAvatar from '../ui/VnAvatar.vue';
|
|
import VnLogValue from './VnLogValue.vue';
|
|
import VnUserLink from '../ui/VnUserLink.vue';
|
|
import VnPaginate from '../ui/VnPaginate.vue';
|
|
import VnLogFilter from 'src/components/common/VnLogFilter.vue';
|
|
import RightMenu from './RightMenu.vue';
|
|
import { useFilterParams } from 'src/composables/useFilterParams';
|
|
|
|
const stateStore = useStateStore();
|
|
const validationsStore = useValidator();
|
|
const { models } = validationsStore;
|
|
const route = useRoute();
|
|
const router = useRouter();
|
|
const { t } = useI18n();
|
|
const props = defineProps({
|
|
model: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
url: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
mapper: {
|
|
type: Function,
|
|
default: null,
|
|
},
|
|
});
|
|
|
|
const filter = {
|
|
fields: [
|
|
'id',
|
|
'originFk',
|
|
'userFk',
|
|
'action',
|
|
'changedModel',
|
|
'oldInstance',
|
|
'newInstance',
|
|
'creationDate',
|
|
'changedModel',
|
|
'changedModelId',
|
|
'changedModelValue',
|
|
'description',
|
|
'summaryId',
|
|
],
|
|
include: [
|
|
{
|
|
relation: 'user',
|
|
scope: {
|
|
fields: ['nickname', 'name', 'image'],
|
|
include: {
|
|
relation: 'worker',
|
|
scope: {
|
|
fields: ['id'],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
where: { and: [{ originFk: route.params.id }] },
|
|
};
|
|
|
|
const paginate = ref();
|
|
const dataKey = computed(() => `${props.model}Log`);
|
|
const userParams = ref(useFilterParams(dataKey.value).params);
|
|
|
|
let validations = models;
|
|
let pointRecord = ref(null);
|
|
let byRecord = ref(false);
|
|
const logTree = ref([]);
|
|
|
|
const actionsText = {
|
|
insert: 'Creates',
|
|
update: 'Edits',
|
|
delete: 'Deletes',
|
|
select: 'Accesses',
|
|
};
|
|
const actionsClass = {
|
|
insert: 'success',
|
|
update: 'warning',
|
|
delete: 'alert',
|
|
select: 'notice',
|
|
};
|
|
const actionsIcon = {
|
|
insert: 'add',
|
|
update: 'edit',
|
|
delete: 'remove',
|
|
select: 'visibility',
|
|
};
|
|
const validDate = new RegExp(
|
|
/^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])/.source +
|
|
/T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$/.source,
|
|
);
|
|
|
|
function castJsonValue(value) {
|
|
return typeof value === 'string' && validDate.test(value) ? new Date(value) : value;
|
|
}
|
|
|
|
function parseProps(propNames, locale, vals, olds) {
|
|
const props = [];
|
|
|
|
for (const prop of propNames) {
|
|
if (prop.endsWith('$')) continue;
|
|
props.push({
|
|
name: prop,
|
|
nameI18n: useCapitalize(locale.columns?.[prop]) || prop,
|
|
val: getVal(vals, prop),
|
|
old: olds && getVal(olds, prop),
|
|
});
|
|
}
|
|
props.sort((a, b) => a.nameI18n.localeCompare(b.nameI18n));
|
|
|
|
function getVal(vals, prop) {
|
|
let val;
|
|
let id;
|
|
const showProp = `${prop}$`;
|
|
|
|
if (vals[showProp] != null) {
|
|
val = vals[showProp];
|
|
id = vals[prop];
|
|
} else val = vals[prop];
|
|
|
|
return { val: castJsonValue(val), id };
|
|
}
|
|
|
|
return props;
|
|
}
|
|
|
|
function getLogTree(data) {
|
|
const logs = [];
|
|
let originLog = null;
|
|
let userLog = null;
|
|
let modelLog = null;
|
|
let nLogs;
|
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
let log = data[i];
|
|
let prevLog = i > 0 ? data[i - 1] : null;
|
|
const locale = validations[log.changedModel]?.locale || {};
|
|
|
|
// Origin
|
|
const originChanged = !prevLog || log.originFk != prevLog.originFk;
|
|
if (originChanged) {
|
|
logs.push((originLog = { originFk: log.originFk, logs: [] }));
|
|
}
|
|
// User
|
|
const userChanged = originChanged || log.userFk != prevLog.userFk;
|
|
if (userChanged) {
|
|
originLog.logs.push(
|
|
(userLog = {
|
|
user: log.user,
|
|
userFk: log.userFk,
|
|
logs: [],
|
|
}),
|
|
);
|
|
}
|
|
// Model
|
|
const modelChanged =
|
|
userChanged ||
|
|
log.changedModel != prevLog.changedModel ||
|
|
log.changedModelId != prevLog.changedModelId ||
|
|
nLogs >= 6;
|
|
|
|
if (modelChanged) {
|
|
userLog.logs.push(
|
|
(modelLog = {
|
|
model: log.changedModel,
|
|
modelI18n: useCapitalize(locale.name) || log.changedModel,
|
|
id: log.changedModelId,
|
|
showValue: log.changedModelValue,
|
|
logs: [],
|
|
}),
|
|
);
|
|
nLogs = 0;
|
|
}
|
|
nLogs++;
|
|
modelLog.logs.push(log);
|
|
modelLog.summaryId = modelLog.logs[0].summaryId;
|
|
// Changes
|
|
const notDelete = log.action != 'delete';
|
|
const olds = (notDelete ? log.oldInstance : null) || {};
|
|
const vals = (notDelete ? log.newInstance : log.oldInstance) || {};
|
|
|
|
let propNames = Object.keys(olds).concat(Object.keys(vals));
|
|
propNames = [...new Set(propNames)];
|
|
|
|
log.props = parseProps(propNames, locale, vals, olds);
|
|
}
|
|
return logs;
|
|
}
|
|
|
|
async function openPointRecord(id, modelLog) {
|
|
pointRecord.value = null;
|
|
const { data } = await axios.get(`${props.model}Logs/${id}/pitInstance`);
|
|
const propNames = Object.keys(data);
|
|
const locale = validations[modelLog.model]?.locale || {};
|
|
pointRecord.value = parseProps(propNames, locale, data);
|
|
}
|
|
async function setLogTree(data) {
|
|
if (!data) return;
|
|
logTree.value = getLogTree(data);
|
|
}
|
|
|
|
function filterByRecord(modelLog) {
|
|
byRecord.value = true;
|
|
const { id, model } = modelLog;
|
|
applyFilter({ changedModelId: id, changedModel: model });
|
|
}
|
|
|
|
async function applyFilter(params = {}) {
|
|
paginate.value.arrayData.resetPagination();
|
|
paginate.value.arrayData.applyFilter({
|
|
filter: {},
|
|
params: { originFk: route.params.id, ...params },
|
|
});
|
|
}
|
|
|
|
function exprBuilder(param, value) {
|
|
switch (param) {
|
|
case 'changedModelValue':
|
|
return { [param]: { like: `%${value}%` } };
|
|
case 'change':
|
|
if (value)
|
|
return {
|
|
or: [
|
|
{ oldJson: { like: `%${value}%` } },
|
|
{ newJson: { like: `%${value}%` } },
|
|
{ description: { like: `%${value}%` } },
|
|
],
|
|
};
|
|
break;
|
|
case 'action':
|
|
if (value?.length) return { [param]: { inq: value } };
|
|
break;
|
|
case 'from':
|
|
return { creationDate: { gte: value } };
|
|
case 'to':
|
|
return { creationDate: { lte: value } };
|
|
case 'userType':
|
|
if (value === 'User') return { userFk: { neq: null } };
|
|
if (value === 'System') return { userFk: null };
|
|
break;
|
|
default:
|
|
return { [param]: value };
|
|
}
|
|
}
|
|
|
|
async function clearFilter() {
|
|
byRecord.value = false;
|
|
await applyFilter();
|
|
}
|
|
|
|
onMounted(() => {
|
|
stateStore.rightDrawerChangeValue(true);
|
|
});
|
|
onUnmounted(() => {
|
|
stateStore.rightDrawer = false;
|
|
});
|
|
|
|
watch(
|
|
() => router.currentRoute.value.params.id,
|
|
() => {
|
|
applyFilter();
|
|
},
|
|
);
|
|
</script>
|
|
<template>
|
|
<VnPaginate
|
|
ref="paginate"
|
|
:data-key
|
|
:url="dataKey + 's'"
|
|
:user-filter="filter"
|
|
:skeleton="false"
|
|
auto-load
|
|
@on-fetch="setLogTree"
|
|
@on-change="setLogTree"
|
|
search-url="logs"
|
|
:exprBuilder
|
|
:order="['creationDate DESC', 'id DESC']"
|
|
>
|
|
<template #body>
|
|
<div
|
|
class="column items-center logs origin-log q-mt-md"
|
|
v-for="(originLog, originLogIndex) in logTree"
|
|
:key="originLogIndex"
|
|
>
|
|
<QItem class="origin-info items-center q-my-md" v-if="logTree.length > 1">
|
|
<h6 class="origin-id text-grey">
|
|
{{ useCapitalize(validations[props.model].locale.name) }}
|
|
#{{ originLog.originFk }}
|
|
</h6>
|
|
<div class="line bg-grey"></div>
|
|
</QItem>
|
|
<div
|
|
class="user-log q-mb-sm"
|
|
v-for="(userLog, userIndex) in originLog.logs"
|
|
:key="userIndex"
|
|
>
|
|
<div class="timeline">
|
|
<div class="user-avatar">
|
|
<VnUserLink :worker-id="userLog?.user?.id">
|
|
<template #link>
|
|
<VnAvatar
|
|
:class="{ 'cursor-pointer': userLog?.user?.id }"
|
|
:worker-id="userLog?.user?.id"
|
|
:title="userLog?.user?.nickname"
|
|
:show-letter="!userLog?.user"
|
|
size="lg"
|
|
/>
|
|
</template>
|
|
</VnUserLink>
|
|
</div>
|
|
<div class="arrow bg-panel" v-if="byRecord"></div>
|
|
<div class="line"></div>
|
|
</div>
|
|
<QList class="user-changes" v-if="userLog">
|
|
<QItem
|
|
class="model-log column q-px-none q-py-xs"
|
|
v-for="(modelLog, modelLogIndex) in userLog.logs"
|
|
:key="modelLogIndex"
|
|
>
|
|
<QItemSection>
|
|
<QItemLabel class="model-info q-mb-xs" v-if="!byRecord">
|
|
<QChip
|
|
dense
|
|
size="md"
|
|
class="model-name q-mr-xs text-white"
|
|
v-if="
|
|
!(
|
|
modelLog.changedModel &&
|
|
modelLog.changedModelId
|
|
) && modelLog.model
|
|
"
|
|
:style="{
|
|
backgroundColor: useColor(modelLog.model),
|
|
}"
|
|
:title="`${modelLog.model} #${modelLog.id}`"
|
|
data-cy="vnLog-model-chip"
|
|
>
|
|
{{ t(modelLog.modelI18n) }}
|
|
</QChip>
|
|
|
|
<span
|
|
class="model-id q-mr-xs"
|
|
v-if="modelLog.summaryId"
|
|
v-text="`#${modelLog.summaryId}`"
|
|
/>
|
|
<span
|
|
class="model-value"
|
|
:title="modelLog.showValue"
|
|
v-text="modelLog.showValue"
|
|
/>
|
|
<QBtn
|
|
flat
|
|
round
|
|
color="grey"
|
|
class="q-mr-xs q-ml-auto"
|
|
size="sm"
|
|
icon="filter_alt"
|
|
:title="t('recordChanges')"
|
|
@click.stop="filterByRecord(modelLog)"
|
|
/>
|
|
</QItemLabel>
|
|
</QItemSection>
|
|
<QItemSection>
|
|
<QCard
|
|
class="changes-log q-py-none q-mb-xs"
|
|
v-for="(log, logIndex) in modelLog.logs"
|
|
:key="logIndex"
|
|
>
|
|
<QCardSection class="change-info q-pa-none">
|
|
<QItem
|
|
class="q-px-sm q-py-xs justify-between items-center"
|
|
>
|
|
<div
|
|
class="date text-grey text-caption q-mr-sm"
|
|
:title="
|
|
date.formatDate(
|
|
log.creationDate,
|
|
'DD/MM/YYYY hh:mm:ss',
|
|
) ?? `date:'dd/MM/yyyy HH:mm:ss'`
|
|
"
|
|
>
|
|
{{ toRelativeDate(log.creationDate) }}
|
|
</div>
|
|
<div>
|
|
<QBtn
|
|
color="grey"
|
|
class="pit"
|
|
icon="preview"
|
|
flat
|
|
round
|
|
:title="t('pointRecord')"
|
|
padding="none"
|
|
v-if="log.action != 'insert'"
|
|
@click.stop="
|
|
openPointRecord(log.id, modelLog)
|
|
"
|
|
>
|
|
<QPopupProxy>
|
|
<QCard v-if="pointRecord">
|
|
<div
|
|
class="header q-px-sm q-py-xs q-ma-none text-white text-bold bg-primary"
|
|
>
|
|
{{ modelLog.modelI18n }}
|
|
<span v-if="modelLog.id"
|
|
>#{{
|
|
modelLog.id
|
|
}}</span
|
|
>
|
|
</div>
|
|
<QCardSection
|
|
class="change-detail q-pa-sm"
|
|
>
|
|
<QItem
|
|
v-for="(
|
|
value, index
|
|
) in pointRecord"
|
|
:key="index"
|
|
class="q-pa-none"
|
|
>
|
|
<span
|
|
class="json-field q-mr-xs text-grey"
|
|
:title="
|
|
value.name
|
|
"
|
|
>
|
|
{{
|
|
value.nameI18n
|
|
}}:
|
|
</span>
|
|
<VnLogValue
|
|
:value="value.val"
|
|
:name="value.name"
|
|
/>
|
|
</QItem>
|
|
</QCardSection>
|
|
</QCard>
|
|
</QPopupProxy>
|
|
</QBtn>
|
|
<QIcon
|
|
class="action q-ml-xs"
|
|
:class="actionsClass[log.action]"
|
|
:name="actionsIcon[log.action]"
|
|
:title="
|
|
t(
|
|
`actions.${
|
|
actionsText[log.action]
|
|
}`,
|
|
)
|
|
"
|
|
data-cy="vnLog-action-icon"
|
|
/>
|
|
</div>
|
|
</QItem>
|
|
</QCardSection>
|
|
<QCardSection
|
|
class="change-detail q-px-sm q-py-xs"
|
|
:class="{ expanded: log.expand }"
|
|
v-if="log.props.length || log.description"
|
|
>
|
|
<QIcon
|
|
class="cursor-pointer q-mr-md"
|
|
color="grey"
|
|
name="expand_more"
|
|
:title="t('globals.details')"
|
|
size="sm"
|
|
@click="log.expand = !log.expand"
|
|
/>
|
|
<span v-if="log.props.length" class="attributes">
|
|
<span
|
|
v-if="!log.expand"
|
|
class="q-pa-none text-grey"
|
|
>
|
|
<span
|
|
v-for="(prop, propIndex) in log.props"
|
|
:key="propIndex"
|
|
class="basic-json"
|
|
>
|
|
<span
|
|
class="json-field"
|
|
:title="prop.name"
|
|
>
|
|
{{ prop.nameI18n }}:
|
|
</span>
|
|
<VnLogValue
|
|
:value="prop.val"
|
|
:name="prop.name"
|
|
/>
|
|
<span
|
|
v-if="
|
|
propIndex <
|
|
log.props.length - 1
|
|
"
|
|
>,
|
|
</span>
|
|
</span>
|
|
</span>
|
|
<span
|
|
v-if="log.expand"
|
|
class="expanded-json column q-pa-none"
|
|
>
|
|
<div
|
|
v-for="(
|
|
prop, prop2Index
|
|
) in log.props"
|
|
:key="prop2Index"
|
|
class="q-pa-none text-grey"
|
|
>
|
|
<span
|
|
class="json-field"
|
|
:title="prop.name"
|
|
>
|
|
{{ prop.nameI18n }}:
|
|
</span>
|
|
<span v-if="log.action == 'update'">
|
|
<VnLogValue
|
|
:value="prop.old"
|
|
:name="prop.name"
|
|
/>
|
|
<span
|
|
v-if="prop.old.id"
|
|
class="id-value"
|
|
>
|
|
#{{ prop.old.id }}
|
|
</span>
|
|
→
|
|
<VnLogValue
|
|
:value="prop.val"
|
|
:name="prop.name"
|
|
/>
|
|
<span
|
|
v-if="prop.val.id"
|
|
class="id-value"
|
|
>
|
|
#{{ prop.val.id }}
|
|
</span>
|
|
</span>
|
|
<span v-else="prop.old.val">
|
|
<VnLogValue
|
|
:value="prop.val"
|
|
:name="prop.name"
|
|
/>
|
|
<span
|
|
v-if="prop.old.id"
|
|
class="id-value"
|
|
>#{{ prop.old.id }}</span
|
|
>
|
|
</span>
|
|
</div>
|
|
</span>
|
|
</span>
|
|
<span
|
|
v-if="!log.props.length"
|
|
class="description"
|
|
>
|
|
{{ log.description }}
|
|
</span>
|
|
</QCardSection>
|
|
</QCard>
|
|
</QItemSection>
|
|
</QItem>
|
|
</QList>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</VnPaginate>
|
|
<RightMenu>
|
|
<template #right-panel>
|
|
<VnLogFilter :data-key />
|
|
</template>
|
|
</RightMenu>
|
|
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
|
<QBtn
|
|
v-if="Object.keys(userParams).some((filter) => filter !== 'originFk')"
|
|
color="primary"
|
|
icon="filter_alt_off"
|
|
size="md"
|
|
round
|
|
@click="clearFilter"
|
|
/>
|
|
</QPageSticky>
|
|
</template>
|
|
<style lang="scss" scoped>
|
|
.q-card {
|
|
background-color: var(--vn-section-color);
|
|
}
|
|
.q-item {
|
|
min-height: 0px;
|
|
}
|
|
.q-menu {
|
|
display: block;
|
|
|
|
& > .loading {
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
& > .q-card {
|
|
min-width: 180px;
|
|
max-width: 400px;
|
|
|
|
& > .header {
|
|
color: var(--vn-section-color);
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
}
|
|
}
|
|
.origin-log {
|
|
&:first-child > .origin-info {
|
|
margin-top: 0;
|
|
}
|
|
& > .origin-info {
|
|
margin-top: 28px;
|
|
gap: 6px;
|
|
|
|
& > .origin-id {
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
margin: 0;
|
|
}
|
|
& > .line {
|
|
flex-grow: 1;
|
|
height: 2px;
|
|
}
|
|
}
|
|
}
|
|
.user-log {
|
|
display: flex;
|
|
width: 100%;
|
|
max-width: 40em;
|
|
& > .timeline {
|
|
position: relative;
|
|
padding-right: 1px;
|
|
width: 38px;
|
|
min-width: 38px;
|
|
flex-grow: auto;
|
|
& > .arrow {
|
|
height: 8px;
|
|
width: 8px;
|
|
position: absolute;
|
|
transform: rotateY(0deg) rotate(45deg);
|
|
top: 15px;
|
|
right: -4px;
|
|
z-index: 1;
|
|
}
|
|
& > .user-avatar {
|
|
padding: 8px 0;
|
|
margin-top: -8px;
|
|
position: sticky;
|
|
top: 64px;
|
|
}
|
|
& > .line {
|
|
position: absolute;
|
|
background-color: $primary;
|
|
width: 2px;
|
|
left: 19px;
|
|
z-index: -1;
|
|
top: 0;
|
|
bottom: -8px;
|
|
}
|
|
}
|
|
&:last-child > .timeline > .line {
|
|
display: none;
|
|
}
|
|
& > .user-changes {
|
|
flex-grow: 1;
|
|
overflow: hidden;
|
|
}
|
|
}
|
|
.model-log {
|
|
.model-info {
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
min-height: 22px;
|
|
.model-value {
|
|
font-style: italic;
|
|
}
|
|
.model-id {
|
|
color: var(--vn-label-color);
|
|
font-size: 0.9rem;
|
|
}
|
|
.q-btn {
|
|
visibility: hidden;
|
|
float: right;
|
|
}
|
|
}
|
|
|
|
&:hover {
|
|
.model-info {
|
|
.q-btn {
|
|
visibility: visible;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.changes-log {
|
|
width: 100%;
|
|
overflow: hidden;
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
.change-info {
|
|
overflow: hidden;
|
|
background-color: var(--vn-section-color);
|
|
& > .date {
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
& > div {
|
|
white-space: nowrap;
|
|
.action {
|
|
color: black;
|
|
border-radius: 50%;
|
|
padding: 3px;
|
|
font-size: 18px;
|
|
|
|
&.notice {
|
|
background-color: $info;
|
|
}
|
|
&.success {
|
|
background-color: $positive;
|
|
}
|
|
&.warning {
|
|
background-color: $warning;
|
|
}
|
|
&.alert {
|
|
background-color: $negative;
|
|
}
|
|
}
|
|
}
|
|
.q-btn.pit {
|
|
visibility: hidden;
|
|
}
|
|
&:hover .q-btn.pit {
|
|
visibility: visible;
|
|
}
|
|
}
|
|
& > .change-detail {
|
|
position: relative;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
background-color: var(--vn-section-color);
|
|
white-space: nowrap;
|
|
box-sizing: border-box;
|
|
& > .q-icon {
|
|
float: right;
|
|
transition-property: transform, background-color;
|
|
transition-duration: 150ms;
|
|
margin: 0;
|
|
}
|
|
&.expanded {
|
|
text-overflow: initial;
|
|
white-space: initial;
|
|
|
|
& > .q-icon {
|
|
transform: rotate(180deg);
|
|
}
|
|
}
|
|
& > .no-changes {
|
|
font-style: italic;
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
<i18n>
|
|
en:
|
|
to: To
|
|
pointRecord: View record at this point in time
|
|
recordChanges: show all record changes
|
|
tooltips:
|
|
search: Search by id or concept
|
|
changes: Search by changes
|
|
actions:
|
|
Creates: Creates
|
|
Edits: Edits
|
|
Deletes: Deletes
|
|
Accesses: Accesses
|
|
Users:
|
|
User: User
|
|
All: All
|
|
System: System
|
|
properties:
|
|
id: ID
|
|
claimFk: Claim ID
|
|
saleFk: Sale ID
|
|
quantity: Quantity
|
|
observation: Observation
|
|
ticketCreated: Created
|
|
created: Created
|
|
isChargedToMana: Charged to mana
|
|
pickup: Type of pickup
|
|
dmsFk: Document ID
|
|
text: Description
|
|
claimStateFk: Claim State
|
|
workerFk: Worker
|
|
clientFk: Customer
|
|
responsibility: Responsibility
|
|
packages: Packages
|
|
es:
|
|
to: Hasta
|
|
pointRecord: Ver el registro en este punto
|
|
recordChanges: Mostrar todos los cambios realizados en el registro
|
|
tooltips:
|
|
search: Buscar por identificador o concepto
|
|
changes: Buscar por cambios. Los atributos deben buscarse por su nombre interno, para obtenerlo situar el cursor sobre el atributo.
|
|
Audit logs: Historial
|
|
Property: Propiedad
|
|
Before: Antes
|
|
After: Después
|
|
Yes: Si
|
|
Nothing: Nada
|
|
actions:
|
|
Creates: Crea
|
|
Edits: Modifica
|
|
Deletes: Elimina
|
|
Accesses: Accede
|
|
Users:
|
|
User: Usuario
|
|
All: Todo
|
|
System: Sistema
|
|
properties:
|
|
id: ID
|
|
claimFk: ID reclamación
|
|
saleFk: ID linea de venta
|
|
quantity: Cantidad
|
|
observation: Observación
|
|
ticketCreated: Creado
|
|
created: Creado
|
|
isChargedToMana: Cargado a maná
|
|
pickup: Se debe recoger
|
|
dmsFk: ID documento
|
|
text: Descripción
|
|
claimStateFk: Estado de la reclamación
|
|
workerFk: Trabajador
|
|
clientFk: Cliente
|
|
responsibility: Responsabilidad
|
|
packages: Bultos
|
|
</i18n>
|