ui: add B2B olmayan stok (orphans) page
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<div class="col-12 col-md">
|
||||
<div class="text-h6">Marka Sınıflandırma</div>
|
||||
<div class="text-caption text-grey-7">
|
||||
Kaynak: BAGGI_V3 `cdItemAttribute` (ItemTypeCode=1, AttributeTypeCode=10)
|
||||
Kaynak: NEBIM_V3 marka bilgileri
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -371,7 +371,7 @@ const importKeyFieldLabels = [
|
||||
const importFieldMap = {
|
||||
AKTIF: 'is_active',
|
||||
'HESAP AKTIF': 'calc_enabled',
|
||||
'PG YAYIN': 'publish_postgres',
|
||||
'B2B YAYIN': 'publish_postgres',
|
||||
'NEBIM YAYIN': 'publish_nebim',
|
||||
'TRY TOPTAN YUVARLAMA': 'try_wholesale_step',
|
||||
'TRY PERAKENDE MODU': 'try_retail_mode',
|
||||
@@ -454,7 +454,7 @@ const columns = [
|
||||
col('brand_group', 'MARKA GRUBU', 'brand_group', 76, { classes: 'ps-col', headerClasses: 'ps-col' }),
|
||||
col('anchor_mode', 'ANCHOR MODE', 'anchor_mode', 66, { classes: 'ps-col', headerClasses: 'ps-col' }),
|
||||
col('calc_enabled', 'HESAP AKTIF', 'calc_enabled', 66, { classes: 'ps-col', headerClasses: 'ps-col' }),
|
||||
col('publish_postgres', 'PG YAYIN', 'publish_postgres', 62, { classes: 'ps-col', headerClasses: 'ps-col' }),
|
||||
col('publish_postgres', 'B2B YAYIN', 'publish_postgres', 62, { classes: 'ps-col', headerClasses: 'ps-col' }),
|
||||
col('publish_nebim', 'NEBIM YAYIN', 'publish_nebim', 66, { classes: 'ps-col', headerClasses: 'ps-col' }),
|
||||
|
||||
col('try_wholesale_step', 'TRY TOPTAN YUVARLAMA', 'try_wholesale_step', 76, { align: 'right', classes: 'try-col', headerClasses: 'try-col' }),
|
||||
|
||||
@@ -71,6 +71,31 @@
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-fixed kategori">
|
||||
<div class="filter-head">
|
||||
<span>KATEGORI</span>
|
||||
<q-btn dense flat round size="sm" icon="filter_list" :color="activeFilterCount('kategori') ? 'primary' : 'grey-8'">
|
||||
<q-badge v-if="activeFilterCount('kategori')" floating color="primary">{{ activeFilterCount('kategori') }}</q-badge>
|
||||
<q-menu class="column-filter-menu" anchor="bottom left" self="top left">
|
||||
<div class="q-pa-sm">
|
||||
<q-input v-model="filterSearch.kategori" dense outlined clearable placeholder="Ara" autofocus />
|
||||
<div class="row q-gutter-xs q-mt-sm">
|
||||
<q-btn dense flat size="sm" label="Tumu" @click="selectAllFilter('kategori')" />
|
||||
<q-btn dense flat size="sm" label="Temizle" @click="clearFilter('kategori')" />
|
||||
</div>
|
||||
<q-separator class="q-my-sm" />
|
||||
<q-option-group
|
||||
v-model="columnFilters.kategori"
|
||||
:options="filteredFilterOptions('kategori')"
|
||||
type="checkbox"
|
||||
dense
|
||||
class="column-filter-options"
|
||||
/>
|
||||
</div>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-fixed renk">
|
||||
<div class="filter-head">
|
||||
<span>RENK</span>
|
||||
@@ -214,6 +239,7 @@
|
||||
>
|
||||
<div class="sub-col model">{{ row.product_code || '-' }}</div>
|
||||
<div class="sub-col desc">{{ row.product_description || '-' }}</div>
|
||||
<div class="sub-col kategori">{{ row.kategori || '-' }}</div>
|
||||
<div class="sub-col renk">
|
||||
<div class="renk-kodu">{{ variantCode(row) }}</div>
|
||||
<div class="renk-aciklama">{{ row.color_title || '-' }}</div>
|
||||
@@ -287,6 +313,7 @@ const errorMessage = ref('')
|
||||
const columnFilters = ref({
|
||||
model: [],
|
||||
desc: [],
|
||||
kategori: [],
|
||||
renk: [],
|
||||
ana: [],
|
||||
alt: [],
|
||||
@@ -295,6 +322,7 @@ const columnFilters = ref({
|
||||
const filterSearch = ref({
|
||||
model: '',
|
||||
desc: '',
|
||||
kategori: '',
|
||||
renk: '',
|
||||
ana: '',
|
||||
alt: '',
|
||||
@@ -341,6 +369,7 @@ const productGroups = computed(() => displayRows.value)
|
||||
const filterOptions = computed(() => ({
|
||||
model: uniqueOptions(rows.value.map(row => row.product_code)),
|
||||
desc: uniqueOptions(rows.value.map(row => row.product_description)),
|
||||
kategori: uniqueOptions(rows.value.map(row => row.kategori)),
|
||||
renk: uniqueOptions(rows.value.map(row => variantCode(row))),
|
||||
ana: uniqueOptions(rows.value.map(row => row.urun_ana_grubu)),
|
||||
alt: uniqueOptions(rows.value.map(row => row.urun_alt_grubu)),
|
||||
@@ -386,6 +415,7 @@ function clearFilter (key) {
|
||||
function rowPassesFilters (row) {
|
||||
return filterMatch('model', row.product_code) &&
|
||||
filterMatch('desc', row.product_description) &&
|
||||
filterMatch('kategori', row.kategori) &&
|
||||
filterMatch('renk', variantCode(row)) &&
|
||||
filterMatch('ana', row.urun_ana_grubu) &&
|
||||
filterMatch('alt', row.urun_alt_grubu) &&
|
||||
@@ -548,7 +578,7 @@ function mapRowSizesToSchema (row) {
|
||||
const rawSizeLabels = sizeEntries.map(([rawSize]) => normalizeBedenLabel(rawSize))
|
||||
const schemaMap = getSchemaMap()
|
||||
const grpKey = detectRowGroupKey(row, rawSizeLabels)
|
||||
const schema = grpKey && schemaMap?.[grpKey] ? schemaMap[grpKey] : null
|
||||
const schema = pickSchemaForRow(schemaMap, grpKey, rawSizeLabels)
|
||||
const schemaLabelMap = normalizedSchemaLabelMap(schema)
|
||||
const mapped = {}
|
||||
|
||||
@@ -569,6 +599,26 @@ function mapRowSizesToSchema (row) {
|
||||
return { grpKey, schema, mapped }
|
||||
}
|
||||
|
||||
function pickSchemaForRow (schemaMap, grpKey, rawSizeLabels) {
|
||||
const primary = grpKey && schemaMap?.[grpKey] ? schemaMap[grpKey] : null
|
||||
const rawSet = new Set((rawSizeLabels || []).map(v => normalizeBedenLabel(v)).filter(Boolean))
|
||||
if (!rawSet.size) return primary
|
||||
const primarySet = new Set((primary?.values || []).map(v => normalizeBedenLabel(v)))
|
||||
if ([...rawSet].some(v => primarySet.has(v))) return primary
|
||||
|
||||
let best = primary
|
||||
let bestScore = 0
|
||||
for (const schema of Object.values(schemaMap || {})) {
|
||||
const schemaSet = new Set((schema?.values || []).map(v => normalizeBedenLabel(v)))
|
||||
const score = [...rawSet].reduce((sum, v) => sum + (schemaSet.has(v) ? 1 : 0), 0)
|
||||
if (score > bestScore) {
|
||||
best = schema
|
||||
bestScore = score
|
||||
}
|
||||
}
|
||||
return best
|
||||
}
|
||||
|
||||
function formatQty (value) {
|
||||
const n = Number(value || 0)
|
||||
if (!Number.isFinite(n) || n === 0) return ''
|
||||
@@ -605,7 +655,7 @@ function escapeHtml (value) {
|
||||
function exportVisibleExcel () {
|
||||
const groups = schemaRows.value
|
||||
const rowSpan = Math.max(groups.length, 1)
|
||||
const leftHeaders = ['MODEL', 'DESC', 'RENK', 'URUN ANA GRUBU', 'URUN ALT GRUBU', 'MARKA']
|
||||
const leftHeaders = ['MODEL', 'DESC', 'KATEGORI', 'RENK', 'URUN ANA GRUBU', 'URUN ALT GRUBU', 'MARKA']
|
||||
const headerRows = (groups.length ? groups : [{ key: 'tak', title: 'TAKIM ELBISE', values: [] }]).map((grp, index) => {
|
||||
const left = index === 0
|
||||
? leftHeaders.map(h => `<th rowspan="${rowSpan}">${escapeHtml(h)}</th>`).join('')
|
||||
@@ -631,6 +681,7 @@ function exportVisibleExcel () {
|
||||
return `<tr>
|
||||
<td>${escapeHtml(row.product_code || '')}</td>
|
||||
<td>${escapeHtml(row.product_description || '')}</td>
|
||||
<td>${escapeHtml(row.kategori || '')}</td>
|
||||
<td>${escapeHtml(variantCode(row))}</td>
|
||||
<td>${escapeHtml(row.urun_ana_grubu || '')}</td>
|
||||
<td>${escapeHtml(row.urun_alt_grubu || '')}</td>
|
||||
@@ -665,6 +716,7 @@ onMounted(async () => {
|
||||
--psq-sticky-offset: 12px;
|
||||
--grp-title-w: 90px;
|
||||
--col-desc: var(--col-aciklama);
|
||||
--col-kategori-series: 86px;
|
||||
--col-marka-series: var(--col-marka, 90px);
|
||||
--psq-header-h: var(--grid-header-h);
|
||||
--series-total-w: 76px;
|
||||
@@ -681,6 +733,7 @@ onMounted(async () => {
|
||||
grid-template-columns:
|
||||
var(--col-model)
|
||||
var(--col-desc)
|
||||
var(--col-kategori-series)
|
||||
var(--col-renk)
|
||||
var(--col-ana)
|
||||
var(--col-alt)
|
||||
@@ -774,11 +827,11 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.total-header-cell {
|
||||
grid-column: 8 / 9;
|
||||
grid-column: 9 / 10;
|
||||
}
|
||||
|
||||
.series-header-cell {
|
||||
grid-column: 9 / 10;
|
||||
grid-column: 10 / 11;
|
||||
}
|
||||
|
||||
.series-flat-row {
|
||||
@@ -816,12 +869,14 @@ onMounted(async () => {
|
||||
|
||||
.series-flat-row .sub-col.model { grid-column: 1; }
|
||||
.series-flat-row .sub-col.desc { grid-column: 2; }
|
||||
.series-flat-row .sub-col.renk { grid-column: 3; }
|
||||
.series-flat-row .sub-col.ana { grid-column: 4; }
|
||||
.series-flat-row .sub-col.alt { grid-column: 5; }
|
||||
.series-flat-row .sub-col.marka { grid-column: 6; }
|
||||
.series-flat-row .sub-col.kategori { grid-column: 3; }
|
||||
.series-flat-row .sub-col.renk { grid-column: 4; }
|
||||
.series-flat-row .sub-col.ana { grid-column: 5; }
|
||||
.series-flat-row .sub-col.alt { grid-column: 6; }
|
||||
.series-flat-row .sub-col.marka { grid-column: 7; }
|
||||
|
||||
.series-flat-row .sub-col.model,
|
||||
.series-flat-row .sub-col.kategori,
|
||||
.series-flat-row .sub-col.renk,
|
||||
.series-flat-row .sub-col.ana,
|
||||
.series-flat-row .sub-col.alt,
|
||||
@@ -851,7 +906,7 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.flat-size-cells {
|
||||
grid-column: 7;
|
||||
grid-column: 8;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-auto-columns: var(--beden-w);
|
||||
@@ -893,7 +948,7 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.total-cell {
|
||||
grid-column: 8;
|
||||
grid-column: 9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
@@ -906,7 +961,7 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.series-select-cell {
|
||||
grid-column: 9 / 10;
|
||||
grid-column: 10 / 11;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
@@ -70,6 +70,31 @@
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-fixed kategori">
|
||||
<div class="filter-head">
|
||||
<span>KATEGORI</span>
|
||||
<q-btn dense flat round size="sm" icon="filter_list" :color="activeFilterCount('kategori') ? 'primary' : 'grey-8'">
|
||||
<q-badge v-if="activeFilterCount('kategori')" floating color="primary">{{ activeFilterCount('kategori') }}</q-badge>
|
||||
<q-menu class="column-filter-menu" anchor="bottom left" self="top left">
|
||||
<div class="q-pa-sm">
|
||||
<q-input v-model="filterSearch.kategori" dense outlined clearable placeholder="Ara" autofocus />
|
||||
<div class="row q-gutter-xs q-mt-sm">
|
||||
<q-btn dense flat size="sm" label="Tumu" @click="selectAllFilter('kategori')" />
|
||||
<q-btn dense flat size="sm" label="Temizle" @click="clearFilter('kategori')" />
|
||||
</div>
|
||||
<q-separator class="q-my-sm" />
|
||||
<q-option-group
|
||||
v-model="columnFilters.kategori"
|
||||
:options="filteredFilterOptions('kategori')"
|
||||
type="checkbox"
|
||||
dense
|
||||
class="column-filter-options"
|
||||
/>
|
||||
</div>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-fixed renk">
|
||||
<div class="filter-head">
|
||||
<span>RENK</span>
|
||||
@@ -212,6 +237,7 @@
|
||||
>
|
||||
<div class="sub-col model">{{ row.product_code || '-' }}</div>
|
||||
<div class="sub-col desc">{{ row.product_description || '-' }}</div>
|
||||
<div class="sub-col kategori">{{ row.kategori || '-' }}</div>
|
||||
<div class="sub-col renk">
|
||||
<div class="renk-kodu">{{ variantCode(row) }}</div>
|
||||
<div class="renk-aciklama">{{ row.color_title || '-' }}</div>
|
||||
@@ -273,6 +299,7 @@ const errorMessage = ref('')
|
||||
const columnFilters = ref({
|
||||
model: [],
|
||||
desc: [],
|
||||
kategori: [],
|
||||
renk: [],
|
||||
ana: [],
|
||||
alt: [],
|
||||
@@ -281,6 +308,7 @@ const columnFilters = ref({
|
||||
const filterSearch = ref({
|
||||
model: '',
|
||||
desc: '',
|
||||
kategori: '',
|
||||
renk: '',
|
||||
ana: '',
|
||||
alt: '',
|
||||
@@ -325,6 +353,7 @@ const productGroups = computed(() => displayRows.value)
|
||||
const filterOptions = computed(() => ({
|
||||
model: uniqueOptions(rows.value.map(row => row.product_code)),
|
||||
desc: uniqueOptions(rows.value.map(row => row.product_description)),
|
||||
kategori: uniqueOptions(rows.value.map(row => row.kategori)),
|
||||
renk: uniqueOptions(rows.value.map(row => variantCode(row))),
|
||||
ana: uniqueOptions(rows.value.map(row => row.urun_ana_grubu)),
|
||||
alt: uniqueOptions(rows.value.map(row => row.urun_alt_grubu)),
|
||||
@@ -370,6 +399,7 @@ function clearFilter (key) {
|
||||
function rowPassesFilters (row) {
|
||||
return filterMatch('model', row.product_code) &&
|
||||
filterMatch('desc', row.product_description) &&
|
||||
filterMatch('kategori', row.kategori) &&
|
||||
filterMatch('renk', variantCode(row)) &&
|
||||
filterMatch('ana', row.urun_ana_grubu) &&
|
||||
filterMatch('alt', row.urun_alt_grubu) &&
|
||||
@@ -492,7 +522,7 @@ function mapRowSizesToSchema (row) {
|
||||
const rawSizeLabels = sizeEntries.map(([rawSize]) => normalizeBedenLabel(rawSize))
|
||||
const schemaMap = getSchemaMap()
|
||||
const grpKey = detectRowGroupKey(row, rawSizeLabels)
|
||||
const schema = grpKey && schemaMap?.[grpKey] ? schemaMap[grpKey] : null
|
||||
const schema = pickSchemaForRow(schemaMap, grpKey, rawSizeLabels)
|
||||
const schemaLabelMap = normalizedSchemaLabelMap(schema)
|
||||
const mapped = {}
|
||||
|
||||
@@ -513,6 +543,26 @@ function mapRowSizesToSchema (row) {
|
||||
return { grpKey, schema, mapped }
|
||||
}
|
||||
|
||||
function pickSchemaForRow (schemaMap, grpKey, rawSizeLabels) {
|
||||
const primary = grpKey && schemaMap?.[grpKey] ? schemaMap[grpKey] : null
|
||||
const rawSet = new Set((rawSizeLabels || []).map(v => normalizeBedenLabel(v)).filter(Boolean))
|
||||
if (!rawSet.size) return primary
|
||||
const primarySet = new Set((primary?.values || []).map(v => normalizeBedenLabel(v)))
|
||||
if ([...rawSet].some(v => primarySet.has(v))) return primary
|
||||
|
||||
let best = primary
|
||||
let bestScore = 0
|
||||
for (const schema of Object.values(schemaMap || {})) {
|
||||
const schemaSet = new Set((schema?.values || []).map(v => normalizeBedenLabel(v)))
|
||||
const score = [...rawSet].reduce((sum, v) => sum + (schemaSet.has(v) ? 1 : 0), 0)
|
||||
if (score > bestScore) {
|
||||
best = schema
|
||||
bestScore = score
|
||||
}
|
||||
}
|
||||
return best
|
||||
}
|
||||
|
||||
function formatQty (value) {
|
||||
const n = Number(value || 0)
|
||||
if (!Number.isFinite(n) || n === 0) return ''
|
||||
@@ -544,7 +594,7 @@ function csvEscape (v) {
|
||||
}
|
||||
|
||||
function exportVisibleExcel () {
|
||||
const cols = ['MODEL', 'DESC', 'RENK', 'URUN ANA GRUBU', 'URUN ALT GRUBU', 'MARKA']
|
||||
const cols = ['MODEL', 'DESC', 'KATEGORI', 'RENK', 'URUN ANA GRUBU', 'URUN ALT GRUBU', 'MARKA']
|
||||
const sizeCols = schemaRows.value.flatMap(grp => paddedSchemaValues(grp).map(v => (v.ghost ? '' : v.value))).filter(Boolean)
|
||||
cols.push(...sizeCols)
|
||||
cols.push('TOPLAM', 'SERI', 'UYARI')
|
||||
@@ -559,6 +609,7 @@ function exportVisibleExcel () {
|
||||
lines.push([
|
||||
row.product_code || '',
|
||||
row.product_description || '',
|
||||
row.kategori || '',
|
||||
variantCode(row),
|
||||
row.urun_ana_grubu || '',
|
||||
row.urun_alt_grubu || '',
|
||||
@@ -590,6 +641,7 @@ onMounted(() => reload())
|
||||
--psq-sticky-offset: 12px;
|
||||
--grp-title-w: 90px;
|
||||
--col-desc: var(--col-aciklama);
|
||||
--col-kategori-series: 86px;
|
||||
--col-marka-series: var(--col-marka, 90px);
|
||||
--psq-header-h: var(--grid-header-h);
|
||||
--series-total-w: 76px;
|
||||
@@ -606,6 +658,7 @@ onMounted(() => reload())
|
||||
grid-template-columns:
|
||||
var(--col-model)
|
||||
var(--col-desc)
|
||||
var(--col-kategori-series)
|
||||
var(--col-renk)
|
||||
var(--col-ana)
|
||||
var(--col-alt)
|
||||
@@ -699,11 +752,11 @@ onMounted(() => reload())
|
||||
}
|
||||
|
||||
.total-header-cell {
|
||||
grid-column: 8 / 9;
|
||||
grid-column: 9 / 10;
|
||||
}
|
||||
|
||||
.series-header-cell {
|
||||
grid-column: 9 / 10;
|
||||
grid-column: 10 / 11;
|
||||
}
|
||||
|
||||
.series-flat-row {
|
||||
@@ -741,12 +794,14 @@ onMounted(() => reload())
|
||||
|
||||
.series-flat-row .sub-col.model { grid-column: 1; }
|
||||
.series-flat-row .sub-col.desc { grid-column: 2; }
|
||||
.series-flat-row .sub-col.renk { grid-column: 3; }
|
||||
.series-flat-row .sub-col.ana { grid-column: 4; }
|
||||
.series-flat-row .sub-col.alt { grid-column: 5; }
|
||||
.series-flat-row .sub-col.marka { grid-column: 6; }
|
||||
.series-flat-row .sub-col.kategori { grid-column: 3; }
|
||||
.series-flat-row .sub-col.renk { grid-column: 4; }
|
||||
.series-flat-row .sub-col.ana { grid-column: 5; }
|
||||
.series-flat-row .sub-col.alt { grid-column: 6; }
|
||||
.series-flat-row .sub-col.marka { grid-column: 7; }
|
||||
|
||||
.series-flat-row .sub-col.model,
|
||||
.series-flat-row .sub-col.kategori,
|
||||
.series-flat-row .sub-col.renk,
|
||||
.series-flat-row .sub-col.ana,
|
||||
.series-flat-row .sub-col.alt,
|
||||
@@ -776,7 +831,7 @@ onMounted(() => reload())
|
||||
}
|
||||
|
||||
.flat-size-cells {
|
||||
grid-column: 7;
|
||||
grid-column: 8;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-auto-columns: var(--beden-w);
|
||||
@@ -818,7 +873,7 @@ onMounted(() => reload())
|
||||
}
|
||||
|
||||
.total-cell {
|
||||
grid-column: 8;
|
||||
grid-column: 9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
@@ -831,7 +886,7 @@ onMounted(() => reload())
|
||||
}
|
||||
|
||||
.series-select-cell {
|
||||
grid-column: 9 / 10;
|
||||
grid-column: 10 / 11;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
@@ -840,7 +840,7 @@
|
||||
<div>
|
||||
<div class="text-subtitle1 text-weight-bold">Fiyat Kontrolu (Satinalma Ortalama)</div>
|
||||
<div class="text-caption text-grey-7">
|
||||
BAGGI_V3 satinalma gecmisindeki son 10 USD ortalamasindan %10'dan fazla sapan tum satirlar.
|
||||
NEBIM_V3 satinalma gecmisindeki son 10 USD ortalamasindan %10'dan fazla sapan tum satirlar.
|
||||
</div>
|
||||
</div>
|
||||
<q-badge color="primary" outline>{{ priceDeviationRows.length }} satir</q-badge>
|
||||
@@ -1105,6 +1105,7 @@ import { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'
|
||||
import { usePermission } from 'src/composables/usePermission'
|
||||
import { get, post, download, extractApiErrorDetail } from 'src/services/api'
|
||||
import { createTraceId, slog } from 'src/utils/slog'
|
||||
import { formatDataSourceLabel } from 'src/utils/formatters'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@@ -2334,8 +2335,8 @@ function resolveHistorySourceType (item, forcedType = '') {
|
||||
}
|
||||
|
||||
function resolveHistorySourceLabel (sourceType) {
|
||||
if (sourceType === 'purchase') return 'BAGGI_V3'
|
||||
if (sourceType === 'recipe') return 'URETIM'
|
||||
if (sourceType === 'purchase') return formatDataSourceLabel('BAGGI_V3')
|
||||
if (sourceType === 'recipe') return formatDataSourceLabel('URETIM')
|
||||
return 'HISTORY'
|
||||
}
|
||||
|
||||
@@ -4770,7 +4771,7 @@ async function confirmBrPriceDeviationIfNeeded () {
|
||||
html: true,
|
||||
message: `
|
||||
<div style="margin-bottom:10px;">
|
||||
Bazı satırlarda girilen fiyat, BAGGI_V3 satınalma geçmişindeki <b>son 10</b> kaydın USD ortalamasından <b>%10</b>'dan fazla sapıyor.
|
||||
Bazı satırlarda girilen fiyat, NEBIM_V3 satınalma geçmişindeki <b>son 10</b> kaydın USD ortalamasından <b>%10</b>'dan fazla sapıyor.
|
||||
</div>
|
||||
<div style="max-height: 360px; overflow:auto; border:1px solid #e0e0e0; border-radius:6px;">
|
||||
<table style="width:100%; border-collapse:collapse; font-size:13px;">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="col">
|
||||
<div class="text-h6">Maliyet Parca Eslestirme</div>
|
||||
<div class="text-caption text-grey-7">
|
||||
V3 Urun Ilk Grubu (42. ozellik) + Urun Ana/Alt Grup + URETIM Parca Bolum + Hammadde Turleri eslestirmesi (URETIM mk_ tablolarinda tutulur)
|
||||
NEBIM_V3 urun gruplari + TEDARIK URETIM PROGRAMI parca bolum + hammadde turleri eslestirmesi
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -207,6 +207,7 @@ import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { useQuasar } from 'quasar'
|
||||
import { usePermission } from 'src/composables/usePermission'
|
||||
import { useTranslationStore } from 'src/stores/translationStore'
|
||||
import { formatDataSourceLabel } from 'src/utils/formatters'
|
||||
|
||||
const $q = useQuasar()
|
||||
const store = useTranslationStore()
|
||||
@@ -231,15 +232,10 @@ const tablePagination = ref({
|
||||
let filterReloadTimer = null
|
||||
|
||||
const sourceTypeOptions = [
|
||||
{ label: 'dummy', value: 'dummy' },
|
||||
{ label: 'postgre', value: 'postgre' },
|
||||
{ label: 'mssql', value: 'mssql' }
|
||||
{ label: formatDataSourceLabel('dummy'), value: 'dummy' },
|
||||
{ label: formatDataSourceLabel('postgre'), value: 'postgre' },
|
||||
{ label: formatDataSourceLabel('mssql'), value: 'mssql' }
|
||||
]
|
||||
const sourceTypeLabelMap = {
|
||||
dummy: 'UI',
|
||||
postgre: 'PostgreSQL',
|
||||
mssql: 'MSSQL'
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{ name: 'actions', label: 'Güncelle', field: 'actions', align: 'left' },
|
||||
@@ -413,7 +409,7 @@ function cellClass (key, field) {
|
||||
|
||||
function sourceTypeLabel (key) {
|
||||
const val = String(rowDraft(key).source_type || 'dummy').toLowerCase()
|
||||
return sourceTypeLabelMap[val] || val || '-'
|
||||
return formatDataSourceLabel(val)
|
||||
}
|
||||
|
||||
function toggleSelected (key, checked) {
|
||||
|
||||
+24
-24
@@ -3,9 +3,8 @@
|
||||
v-if="canReadUser"
|
||||
class="q-pa-md user-sync-page"
|
||||
>
|
||||
|
||||
<div class="row items-center justify-between q-mb-md">
|
||||
<div class="text-h6 text-primary">👤 Kullanıcı Yönetimi</div>
|
||||
<div class="text-h6 text-primary">Kullanici Yonetimi</div>
|
||||
<q-btn
|
||||
v-if="canUpdateUser"
|
||||
color="primary"
|
||||
@@ -20,11 +19,10 @@
|
||||
<q-separator />
|
||||
|
||||
<div class="row q-col-gutter-md q-mt-md">
|
||||
<!-- 🔹 PostgreSQL Kullanıcıları -->
|
||||
<div class="col-6">
|
||||
<q-card flat bordered>
|
||||
<q-card-section class="bg-primary text-white text-subtitle1">
|
||||
PostgreSQL Kullanıcıları
|
||||
B2B Kullanicilari
|
||||
</q-card-section>
|
||||
|
||||
<q-table
|
||||
@@ -36,7 +34,7 @@
|
||||
bordered
|
||||
separator="cell"
|
||||
>
|
||||
<template v-slot:body-cell-sync_status="props">
|
||||
<template #body-cell-sync_status="props">
|
||||
<q-td :props="props">
|
||||
<q-chip
|
||||
:color="statusColor(props.row.sync_status)"
|
||||
@@ -48,23 +46,27 @@
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template v-slot:body-cell-actions="props">
|
||||
<template #body-cell-actions="props">
|
||||
<q-td :props="props">
|
||||
<q-btn
|
||||
v-if="canUpdateUser"
|
||||
dense flat icon="link"
|
||||
dense
|
||||
flat
|
||||
icon="link"
|
||||
color="primary"
|
||||
size="sm"
|
||||
@click="openMapDialog(props.row)"
|
||||
:disable="store.loading || !canUpdateUser"
|
||||
@click="openMapDialog(props.row)"
|
||||
/>
|
||||
<q-btn
|
||||
v-if="canUpdateUser"
|
||||
dense flat icon="link_off"
|
||||
dense
|
||||
flat
|
||||
icon="link_off"
|
||||
color="negative"
|
||||
size="sm"
|
||||
@click="store.unmap(props.row.id)"
|
||||
:disable="store.loading || !props.row.mssql_username || !canUpdateUser"
|
||||
@click="store.unmap(props.row.id)"
|
||||
/>
|
||||
</q-td>
|
||||
</template>
|
||||
@@ -72,11 +74,10 @@
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
<!-- 🔸 MSSQL Kullanıcıları -->
|
||||
<div class="col-6">
|
||||
<q-card flat bordered>
|
||||
<q-card-section class="bg-secondary text-white text-subtitle1">
|
||||
MSSQL Kullanıcıları
|
||||
NEBIM_V3 Kullanicilari
|
||||
</q-card-section>
|
||||
|
||||
<q-table
|
||||
@@ -88,7 +89,7 @@
|
||||
bordered
|
||||
separator="cell"
|
||||
>
|
||||
<template v-slot:body-cell-is_blocked="props">
|
||||
<template #body-cell-is_blocked="props">
|
||||
<q-td :props="props">
|
||||
<q-chip
|
||||
:color="props.row.is_blocked ? 'negative' : 'positive'"
|
||||
@@ -117,9 +118,9 @@
|
||||
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { useUserSyncStore } from 'src/stores/userSyncStore'
|
||||
import { Dialog } from 'quasar'
|
||||
import { usePermission } from 'src/composables/usePermission'
|
||||
import { useUserSyncStore } from 'src/stores/userSyncStore'
|
||||
|
||||
const { canRead, canUpdate } = usePermission()
|
||||
const canReadUser = canRead('user')
|
||||
@@ -132,20 +133,20 @@ const pgColumns = [
|
||||
{ name: 'code', label: 'Kodu', field: 'code', align: 'left' },
|
||||
{ name: 'full_name', label: 'Ad Soyad', field: 'full_name', align: 'left' },
|
||||
{ name: 'email', label: 'E-posta', field: 'email', align: 'left' },
|
||||
{ name: 'mssql_username', label: 'MSSQL Kullanıcı', field: 'mssql_username', align: 'left' },
|
||||
{ name: 'mssql_username', label: 'NEBIM_V3 Kullanicisi', field: 'mssql_username', align: 'left' },
|
||||
{ name: 'sync_status', label: 'Durum', field: 'sync_status', align: 'center' },
|
||||
{ name: 'actions', label: 'İşlemler', field: 'actions', align: 'center' }
|
||||
{ name: 'actions', label: 'Islemler', field: 'actions', align: 'center' }
|
||||
]
|
||||
|
||||
const msColumns = [
|
||||
{ name: 'username', label: 'Kullanıcı Adı', field: 'username', align: 'left' },
|
||||
{ name: 'username', label: 'Kullanici Adi', field: 'username', align: 'left' },
|
||||
{ name: 'first_name', label: 'Ad', field: 'first_name', align: 'left' },
|
||||
{ name: 'last_name', label: 'Soyad', field: 'last_name', align: 'left' },
|
||||
{ name: 'email', label: 'E-posta', field: 'email', align: 'left' },
|
||||
{ name: 'is_blocked', label: 'Durum', field: 'is_blocked', align: 'center' }
|
||||
]
|
||||
|
||||
function statusColor(status) {
|
||||
function statusColor (status) {
|
||||
switch (status) {
|
||||
case 'synced': return 'positive'
|
||||
case 'manual': return 'primary'
|
||||
@@ -155,14 +156,12 @@ function statusColor(status) {
|
||||
}
|
||||
}
|
||||
|
||||
function openMapDialog(pgUser) {
|
||||
if (!canUpdateUser.value) {
|
||||
return
|
||||
}
|
||||
function openMapDialog (pgUser) {
|
||||
if (!canUpdateUser.value) return
|
||||
|
||||
Dialog.create({
|
||||
title: 'Kullanıcı Eşleme',
|
||||
message: 'Bu PostgreSQL kullanıcısını hangi MSSQL kullanıcısına bağlamak istiyorsunuz?',
|
||||
title: 'Kullanici Esleme',
|
||||
message: 'Bu B2B kullanicisini hangi NEBIM_V3 kullanicisina baglamak istiyorsunuz?',
|
||||
options: {
|
||||
type: 'radio',
|
||||
model: '',
|
||||
@@ -186,6 +185,7 @@ onMounted(() => {
|
||||
.user-sync-page {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.q-card-section {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user