Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -114,7 +114,8 @@
|
||||
filled
|
||||
maxlength="13"
|
||||
label="Yeni Urun"
|
||||
@update:model-value="val => onNewItemChange(props.row, val)"
|
||||
:class="newItemInputClass(props.row)"
|
||||
@update:model-value="val => onNewItemChange(props.row, val, 'typed')"
|
||||
>
|
||||
<template #append>
|
||||
<q-icon name="arrow_drop_down" class="cursor-pointer" />
|
||||
@@ -145,6 +146,32 @@
|
||||
</div>
|
||||
</q-menu>
|
||||
</q-input>
|
||||
<div v-if="props.row.NewItemMode && props.row.NewItemMode !== 'empty'" class="q-mt-xs row items-center no-wrap">
|
||||
<q-badge :color="newItemBadgeColor(props.row)" text-color="white">
|
||||
{{ newItemBadgeLabel(props.row) }}
|
||||
</q-badge>
|
||||
<span class="text-caption q-ml-sm text-grey-8">{{ newItemHintText(props.row) }}</span>
|
||||
<q-btn
|
||||
v-if="props.row.NewItemMode === 'new'"
|
||||
class="q-ml-sm"
|
||||
dense
|
||||
flat
|
||||
size="sm"
|
||||
color="warning"
|
||||
label="cdItem Bilgisi"
|
||||
@click="openCdItemDialog(props.row.NewItemCode)"
|
||||
/>
|
||||
<q-btn
|
||||
v-if="props.row.NewItemMode === 'new'"
|
||||
class="q-ml-xs"
|
||||
dense
|
||||
flat
|
||||
size="sm"
|
||||
color="primary"
|
||||
label="Urun Ozellikleri"
|
||||
@click="openAttributeDialog(props.row.NewItemCode)"
|
||||
/>
|
||||
</div>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
@@ -157,13 +184,10 @@
|
||||
option-value="color_code"
|
||||
emit-value
|
||||
map-options
|
||||
use-input
|
||||
new-value-mode="add-unique"
|
||||
dense
|
||||
filled
|
||||
label="Yeni Renk"
|
||||
@update:model-value="() => onNewColorChange(props.row)"
|
||||
@new-value="(val, done) => onCreateColorValue(props.row, val, done)"
|
||||
/>
|
||||
</q-td>
|
||||
</template>
|
||||
@@ -173,16 +197,13 @@
|
||||
<q-select
|
||||
v-model="props.row.NewDim2"
|
||||
:options="getSecondColorOptions(props.row)"
|
||||
option-label="item_dim2_code"
|
||||
option-label="item_dim2_label"
|
||||
option-value="item_dim2_code"
|
||||
emit-value
|
||||
map-options
|
||||
use-input
|
||||
new-value-mode="add-unique"
|
||||
dense
|
||||
filled
|
||||
label="Yeni 2. Renk"
|
||||
@new-value="(val, done) => onCreateSecondColorValue(props.row, val, done)"
|
||||
/>
|
||||
</q-td>
|
||||
</template>
|
||||
@@ -205,6 +226,127 @@
|
||||
<q-banner v-if="store.error" class="bg-red text-white q-mt-sm">
|
||||
Hata: {{ store.error }}
|
||||
</q-banner>
|
||||
|
||||
<q-dialog v-model="cdItemDialogOpen" persistent>
|
||||
<q-card style="min-width: 980px; max-width: 98vw;">
|
||||
<q-card-section class="row items-center q-pb-none">
|
||||
<div class="text-h6">Yeni Kod cdItem Bilgileri</div>
|
||||
<q-space />
|
||||
<q-badge color="warning" text-color="black">
|
||||
{{ cdItemTargetCode || '-' }}
|
||||
</q-badge>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="q-pt-md">
|
||||
<div class="row q-col-gutter-sm">
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.ItemDimTypeCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemDimTypeCodes')" label="ItemDimTypeCode" />
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.ProductTypeCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('productTypeCodes')" label="ProductTypeCode" />
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.ProductHierarchyID" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('productHierarchyIDs')" label="ProductHierarchyID" />
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.UnitOfMeasureCode1" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('unitOfMeasureCode1List')" label="UnitOfMeasureCode1" />
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.ItemAccountGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemAccountGrCodes')" label="ItemAccountGrCode" />
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.ItemTaxGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemTaxGrCodes')" label="ItemTaxGrCode" />
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.ItemPaymentPlanGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemPaymentPlanGrCodes')" label="ItemPaymentPlanGrCode" />
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.ItemDiscountGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemDiscountGrCodes')" label="ItemDiscountGrCode" />
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.ItemVendorGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemVendorGrCodes')" label="ItemVendorGrCode" />
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.PromotionGroupCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('promotionGroupCodes')" label="PromotionGroupCode" />
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.ProductCollectionGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('productCollectionGrCodes')" label="ProductCollectionGrCode" />
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.StorePriceLevelCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('storePriceLevelCodes')" label="StorePriceLevelCode" />
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.PerceptionOfFashionCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('perceptionOfFashionCodes')" label="PerceptionOfFashionCode" />
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.CommercialRoleCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('commercialRoleCodes')" label="CommercialRoleCode" />
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<q-select v-model="cdItemDraftForm.StoreCapacityLevelCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('storeCapacityLevelCodes')" label="StoreCapacityLevelCode" />
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-6">
|
||||
<q-select v-model="cdItemDraftForm.CustomsTariffNumberCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('customsTariffNumbers')" label="CustomsTariffNumberCode" />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<q-select v-model="cdItemDraftForm.CompanyCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('companyCodes')" label="CompanyCode" />
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat label="Vazgec" color="grey-8" v-close-popup />
|
||||
<q-btn color="primary" label="Taslagi Kaydet" @click="saveCdItemDraft" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<q-dialog v-model="attributeDialogOpen" persistent>
|
||||
<q-card style="min-width: 1100px; max-width: 98vw;">
|
||||
<q-card-section class="row items-center q-pb-none">
|
||||
<div class="text-h6">Urun Ozellikleri (2. Pop-up)</div>
|
||||
<q-space />
|
||||
<q-badge color="primary">{{ attributeTargetCode || '-' }}</q-badge>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section style="max-height: 68vh; overflow: auto;">
|
||||
<div class="text-caption text-grey-7 q-mb-sm">
|
||||
Ilk etap dummy: isBlocked=0 kabul edilmis satirlar gibi listelenir.
|
||||
</div>
|
||||
<div
|
||||
v-for="(row, idx) in attributeRows"
|
||||
:key="`${row.AttributeTypeCodeNumber}-${idx}`"
|
||||
class="row q-col-gutter-sm q-mb-xs items-center"
|
||||
>
|
||||
<div class="col-12 col-md-5">
|
||||
<q-input :model-value="row.TypeLabel" dense filled readonly />
|
||||
</div>
|
||||
<div class="col-12 col-md-7">
|
||||
<q-select
|
||||
v-model="row.AttributeCode"
|
||||
dense
|
||||
filled
|
||||
emit-value
|
||||
map-options
|
||||
option-label="label"
|
||||
option-value="value"
|
||||
:options="row.Options"
|
||||
label="AttributeCode - AttributeDescription"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat label="Vazgec" color="grey-8" v-close-popup />
|
||||
<q-btn color="primary" label="Ozellikleri Kaydet" @click="saveAttributeDraft" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
@@ -219,6 +361,8 @@ import { normalizeSearchText } from 'src/utils/searchText'
|
||||
const route = useRoute()
|
||||
const $q = useQuasar()
|
||||
const store = useOrderProductionItemStore()
|
||||
const BAGGI_CODE_PATTERN = /^[A-Z][0-9]{3}-[A-Z]{3}[0-9]{5}$/
|
||||
const BAGGI_CODE_ERROR = 'Girdiginiz kod BAGGI kod sistemine uyumlu degil. Format: X999-XXX99999'
|
||||
|
||||
const orderHeaderID = computed(() => String(route.params.orderHeaderID || '').trim())
|
||||
const header = computed(() => store.header || {})
|
||||
@@ -235,6 +379,12 @@ const descFilter = ref('')
|
||||
const productOptions = ref([])
|
||||
const productSearch = ref('')
|
||||
const selectedMap = ref({})
|
||||
const cdItemDialogOpen = ref(false)
|
||||
const cdItemTargetCode = ref('')
|
||||
const cdItemDraftForm = ref(createEmptyCdItemDraft(''))
|
||||
const attributeDialogOpen = ref(false)
|
||||
const attributeTargetCode = ref('')
|
||||
const attributeRows = ref([])
|
||||
|
||||
const columns = [
|
||||
{ name: 'select', label: '', field: 'select', align: 'center', sortable: false, style: 'width:44px;', headerStyle: 'width:44px;' },
|
||||
@@ -300,24 +450,70 @@ const selectedVisibleCount = computed(() => visibleRowKeys.value.filter(k => !!s
|
||||
const allSelectedVisible = computed(() => visibleRowKeys.value.length > 0 && selectedVisibleCount.value === visibleRowKeys.value.length)
|
||||
const someSelectedVisible = computed(() => selectedVisibleCount.value > 0)
|
||||
|
||||
function onSelectProduct (row, code) {
|
||||
productSearch.value = ''
|
||||
onNewItemChange(row, code)
|
||||
function applyNewItemVisualState (row, source = 'typed') {
|
||||
const info = store.classifyItemCode(row?.NewItemCode || '')
|
||||
row.NewItemCode = info.normalized
|
||||
row.NewItemMode = info.mode
|
||||
row.NewItemSource = info.mode === 'empty' ? '' : source
|
||||
}
|
||||
|
||||
function onNewItemChange (row, val) {
|
||||
function newItemInputClass (row) {
|
||||
return {
|
||||
'new-item-existing': row?.NewItemMode === 'existing',
|
||||
'new-item-new': row?.NewItemMode === 'new'
|
||||
}
|
||||
}
|
||||
|
||||
function newItemBadgeColor (row) {
|
||||
return row?.NewItemMode === 'existing' ? 'positive' : 'warning'
|
||||
}
|
||||
|
||||
function newItemBadgeLabel (row) {
|
||||
return row?.NewItemMode === 'existing' ? 'MEVCUT KOD' : 'YENI KOD'
|
||||
}
|
||||
|
||||
function newItemHintText (row) {
|
||||
if (row?.NewItemMode === 'existing') {
|
||||
return row?.NewItemSource === 'selected'
|
||||
? 'Urun listesinden secildi'
|
||||
: 'Elle girildi (sistemde bulundu)'
|
||||
}
|
||||
if (row?.NewItemMode === 'new') {
|
||||
return store.getCdItemDraft(row?.NewItemCode) ? 'Yeni kod: cdItem taslagi hazir' : 'Yeni kod: cdItem taslagi gerekli'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function onSelectProduct (row, code) {
|
||||
productSearch.value = ''
|
||||
onNewItemChange(row, code, 'selected')
|
||||
}
|
||||
|
||||
function onNewItemChange (row, val, source = 'typed') {
|
||||
const prevCode = String(row?.NewItemCode || '').trim().toUpperCase()
|
||||
const next = String(val || '').trim().toUpperCase()
|
||||
if (next.length > 13) {
|
||||
$q.notify({ type: 'negative', message: 'Model kodu en fazla 13 karakter olabilir.' })
|
||||
row.NewItemCode = next.slice(0, 13)
|
||||
applyNewItemVisualState(row, source)
|
||||
return
|
||||
}
|
||||
if (next.length === 13 && !isValidBaggiModelCode(next)) {
|
||||
$q.notify({ type: 'negative', message: BAGGI_CODE_ERROR })
|
||||
row.NewItemCode = prevCode
|
||||
applyNewItemVisualState(row, source)
|
||||
return
|
||||
}
|
||||
row.NewItemCode = next ? next.toUpperCase() : ''
|
||||
applyNewItemVisualState(row, source)
|
||||
row.NewColor = ''
|
||||
row.NewDim2 = ''
|
||||
if (row.NewItemCode) {
|
||||
store.fetchColors(row.NewItemCode)
|
||||
}
|
||||
if (row.NewItemMode === 'new' && isValidBaggiModelCode(row.NewItemCode) && row.NewItemCode !== prevCode) {
|
||||
openCdItemDialog(row.NewItemCode)
|
||||
}
|
||||
}
|
||||
|
||||
function onNewColorChange (row) {
|
||||
@@ -341,7 +537,11 @@ function getSecondColorOptions (row) {
|
||||
const code = row?.NewItemCode || ''
|
||||
const color = row?.NewColor || ''
|
||||
const key = `${code}::${color}`
|
||||
return store.secondColorOptionsByKey[key] || []
|
||||
const list = store.secondColorOptionsByKey[key] || []
|
||||
return list.map(c => ({
|
||||
...c,
|
||||
item_dim2_label: `${c.item_dim2_code} - ${c.color_description || ''}`.trim()
|
||||
}))
|
||||
}
|
||||
|
||||
function toggleRowSelection (rowKey, checked) {
|
||||
@@ -360,33 +560,12 @@ function toggleSelectAllVisible (checked) {
|
||||
selectedMap.value = next
|
||||
}
|
||||
|
||||
function onCreateColorValue (row, val, done) {
|
||||
const code = normalizeShortCode(val, 3)
|
||||
if (!code) {
|
||||
done(null)
|
||||
return
|
||||
}
|
||||
row.NewColor = code
|
||||
onNewColorChange(row)
|
||||
done(code, 'add-unique')
|
||||
}
|
||||
|
||||
function onCreateSecondColorValue (row, val, done) {
|
||||
const code = normalizeShortCode(val, 3)
|
||||
if (!code) {
|
||||
done(null)
|
||||
return
|
||||
}
|
||||
row.NewDim2 = code
|
||||
done(code, 'add-unique')
|
||||
}
|
||||
|
||||
function normalizeShortCode (value, maxLen) {
|
||||
return String(value || '').trim().toUpperCase().slice(0, maxLen)
|
||||
}
|
||||
|
||||
function isValidBaggiModelCode (code) {
|
||||
return /^[A-Z][0-9]{3}-[A-Z]{3}[0-9]{5}$/.test(code)
|
||||
return BAGGI_CODE_PATTERN.test(code)
|
||||
}
|
||||
|
||||
function validateRowInput (row) {
|
||||
@@ -398,7 +577,7 @@ function validateRowInput (row) {
|
||||
|
||||
if (!newItemCode) return 'Yeni model kodu zorunludur.'
|
||||
if (!isValidBaggiModelCode(newItemCode)) {
|
||||
return 'Girdiginiz yapi BAGGI kod yapisina uygun degildir. Format: X999-XXX99999'
|
||||
return BAGGI_CODE_ERROR
|
||||
}
|
||||
if (oldColor && !newColor) return 'Eski kayitta 1. renk oldugu icin yeni 1. renk zorunludur.'
|
||||
if (newColor && newColor.length !== 3) return 'Yeni 1. renk kodu 3 karakter olmalidir.'
|
||||
@@ -437,6 +616,238 @@ function collectLinesFromRows (selectedRows) {
|
||||
return { errMsg: '', lines }
|
||||
}
|
||||
|
||||
function createEmptyCdItemDraft (itemCode) {
|
||||
return {
|
||||
ItemTypeCode: '1',
|
||||
ItemCode: String(itemCode || '').trim().toUpperCase(),
|
||||
ItemDimTypeCode: '',
|
||||
ProductTypeCode: '',
|
||||
ProductHierarchyID: '',
|
||||
UnitOfMeasureCode1: '',
|
||||
ItemAccountGrCode: '',
|
||||
ItemTaxGrCode: '',
|
||||
ItemPaymentPlanGrCode: '',
|
||||
ItemDiscountGrCode: '',
|
||||
ItemVendorGrCode: '',
|
||||
PromotionGroupCode: '',
|
||||
ProductCollectionGrCode: '',
|
||||
StorePriceLevelCode: '',
|
||||
PerceptionOfFashionCode: '',
|
||||
CommercialRoleCode: '',
|
||||
StoreCapacityLevelCode: '',
|
||||
CustomsTariffNumberCode: '',
|
||||
CompanyCode: ''
|
||||
}
|
||||
}
|
||||
|
||||
function lookupOptions (key) {
|
||||
const list = store.cdItemLookups?.[key] || []
|
||||
return list.map(x => {
|
||||
const code = String(x?.code || '').trim()
|
||||
const desc = String(x?.description || '').trim()
|
||||
return {
|
||||
value: code,
|
||||
label: desc ? `${code} - ${desc}` : code
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function openCdItemDialog (itemCode) {
|
||||
const code = String(itemCode || '').trim().toUpperCase()
|
||||
if (!code) return
|
||||
await store.fetchCdItemLookups()
|
||||
|
||||
cdItemTargetCode.value = code
|
||||
const existing = store.getCdItemDraft(code)
|
||||
const draft = createEmptyCdItemDraft(code)
|
||||
if (existing) {
|
||||
for (const [k, v] of Object.entries(existing)) {
|
||||
if (v == null) continue
|
||||
draft[k] = String(v)
|
||||
}
|
||||
}
|
||||
cdItemDraftForm.value = draft
|
||||
cdItemDialogOpen.value = true
|
||||
}
|
||||
|
||||
function normalizeCdItemDraftForPayload (draftRaw) {
|
||||
const d = draftRaw || {}
|
||||
const toIntOrNil = (v) => {
|
||||
const n = Number(v)
|
||||
return Number.isFinite(n) && n > 0 ? n : null
|
||||
}
|
||||
const toStrOrNil = (v) => {
|
||||
const s = String(v || '').trim()
|
||||
return s || null
|
||||
}
|
||||
return {
|
||||
ItemTypeCode: toIntOrNil(d.ItemTypeCode) || 1,
|
||||
ItemCode: String(d.ItemCode || '').trim().toUpperCase(),
|
||||
ItemDimTypeCode: toIntOrNil(d.ItemDimTypeCode),
|
||||
ProductTypeCode: toIntOrNil(d.ProductTypeCode),
|
||||
ProductHierarchyID: toIntOrNil(d.ProductHierarchyID),
|
||||
UnitOfMeasureCode1: toStrOrNil(d.UnitOfMeasureCode1),
|
||||
ItemAccountGrCode: toStrOrNil(d.ItemAccountGrCode),
|
||||
ItemTaxGrCode: toStrOrNil(d.ItemTaxGrCode),
|
||||
ItemPaymentPlanGrCode: toStrOrNil(d.ItemPaymentPlanGrCode),
|
||||
ItemDiscountGrCode: toStrOrNil(d.ItemDiscountGrCode),
|
||||
ItemVendorGrCode: toStrOrNil(d.ItemVendorGrCode),
|
||||
PromotionGroupCode: toStrOrNil(d.PromotionGroupCode),
|
||||
ProductCollectionGrCode: toStrOrNil(d.ProductCollectionGrCode),
|
||||
StorePriceLevelCode: toStrOrNil(d.StorePriceLevelCode),
|
||||
PerceptionOfFashionCode: toStrOrNil(d.PerceptionOfFashionCode),
|
||||
CommercialRoleCode: toStrOrNil(d.CommercialRoleCode),
|
||||
StoreCapacityLevelCode: toStrOrNil(d.StoreCapacityLevelCode),
|
||||
CustomsTariffNumberCode: toStrOrNil(d.CustomsTariffNumberCode),
|
||||
CompanyCode: toStrOrNil(d.CompanyCode)
|
||||
}
|
||||
}
|
||||
|
||||
function saveCdItemDraft () {
|
||||
const payload = normalizeCdItemDraftForPayload(cdItemDraftForm.value)
|
||||
if (!payload.ItemCode) {
|
||||
$q.notify({ type: 'negative', message: 'ItemCode bos olamaz.' })
|
||||
return
|
||||
}
|
||||
store.setCdItemDraft(payload.ItemCode, payload)
|
||||
cdItemDialogOpen.value = false
|
||||
}
|
||||
|
||||
function createDummyAttributeRows () {
|
||||
const sharedOptions = [
|
||||
{ value: 'DAMATLIK', label: 'DAMATLIK - DAMATLIK' },
|
||||
{ value: 'TAKIM', label: 'TAKIM - TAKIM ELBISE' },
|
||||
{ value: 'CEKET', label: 'CEKET - CEKET' },
|
||||
{ value: 'PANTOLON', label: 'PANTOLON - PANTOLON' }
|
||||
]
|
||||
const rows = [{
|
||||
AttributeTypeCodeNumber: 1,
|
||||
TypeLabel: '1-001 Urun Ana Grubu',
|
||||
AttributeCode: '',
|
||||
Options: sharedOptions
|
||||
}]
|
||||
for (let i = 2; i <= 50; i++) {
|
||||
const code = String(i).padStart(3, '0')
|
||||
rows.push({
|
||||
AttributeTypeCodeNumber: i,
|
||||
TypeLabel: `1-${code} Dummy Ozellik ${i}`,
|
||||
AttributeCode: '',
|
||||
Options: sharedOptions
|
||||
})
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
function buildAttributeRowsFromLookup (list) {
|
||||
const grouped = new Map()
|
||||
for (const it of (list || [])) {
|
||||
const typeCode = Number(it?.attribute_type_code || 0)
|
||||
if (!typeCode) continue
|
||||
if (!grouped.has(typeCode)) {
|
||||
grouped.set(typeCode, {
|
||||
typeCode,
|
||||
typeDesc: String(it?.attribute_type_description || '').trim() || String(typeCode),
|
||||
options: []
|
||||
})
|
||||
}
|
||||
const g = grouped.get(typeCode)
|
||||
const code = String(it?.attribute_code || '').trim()
|
||||
const desc = String(it?.attribute_description || '').trim()
|
||||
g.options.push({
|
||||
value: code,
|
||||
label: `${code} - ${desc || code}`
|
||||
})
|
||||
}
|
||||
|
||||
const rows = [...grouped.values()]
|
||||
.sort((a, b) => a.typeCode - b.typeCode)
|
||||
.map(g => ({
|
||||
AttributeTypeCodeNumber: g.typeCode,
|
||||
TypeLabel: `${g.typeCode}-${g.typeDesc}`,
|
||||
AttributeCode: '',
|
||||
Options: g.options
|
||||
}))
|
||||
return rows
|
||||
}
|
||||
|
||||
async function openAttributeDialog (itemCode) {
|
||||
const code = String(itemCode || '').trim().toUpperCase()
|
||||
if (!code) return
|
||||
attributeTargetCode.value = code
|
||||
const existing = store.getProductAttributeDraft(code)
|
||||
const fetched = await store.fetchProductAttributes(1)
|
||||
const fromLookup = buildAttributeRowsFromLookup(fetched)
|
||||
const baseRows = fromLookup.length ? fromLookup : createDummyAttributeRows()
|
||||
attributeRows.value = Array.isArray(existing) && existing.length
|
||||
? JSON.parse(JSON.stringify(existing))
|
||||
: baseRows
|
||||
attributeDialogOpen.value = true
|
||||
}
|
||||
|
||||
function saveAttributeDraft () {
|
||||
const code = String(attributeTargetCode.value || '').trim().toUpperCase()
|
||||
if (!code) return
|
||||
for (const row of (attributeRows.value || [])) {
|
||||
const selected = String(row?.AttributeCode || '').trim()
|
||||
if (!selected) {
|
||||
$q.notify({ type: 'negative', message: `Urun ozelliklerinde secim zorunlu: ${row?.TypeLabel || ''}` })
|
||||
return
|
||||
}
|
||||
}
|
||||
store.setProductAttributeDraft(code, JSON.parse(JSON.stringify(attributeRows.value || [])))
|
||||
attributeDialogOpen.value = false
|
||||
$q.notify({ type: 'positive', message: 'Urun ozellikleri taslagi kaydedildi.' })
|
||||
}
|
||||
|
||||
function collectProductAttributesFromSelectedRows (selectedRows) {
|
||||
const codeSet = [...new Set(
|
||||
(selectedRows || [])
|
||||
.map(r => String(r?.NewItemCode || '').trim().toUpperCase())
|
||||
.filter(Boolean)
|
||||
)]
|
||||
const out = []
|
||||
|
||||
for (const code of codeSet) {
|
||||
const rows = store.getProductAttributeDraft(code)
|
||||
if (!Array.isArray(rows) || !rows.length) {
|
||||
return { errMsg: `${code} icin urun ozellikleri secilmedi`, productAttributes: [] }
|
||||
}
|
||||
for (const row of rows) {
|
||||
const attributeTypeCode = Number(row?.AttributeTypeCodeNumber || 0)
|
||||
const attributeCode = String(row?.AttributeCode || '').trim()
|
||||
if (!attributeTypeCode || !attributeCode) {
|
||||
return { errMsg: `${code} icin urun ozellikleri eksik`, productAttributes: [] }
|
||||
}
|
||||
out.push({
|
||||
ItemTypeCode: 1,
|
||||
ItemCode: code,
|
||||
AttributeTypeCode: attributeTypeCode,
|
||||
AttributeCode: attributeCode
|
||||
})
|
||||
}
|
||||
}
|
||||
return { errMsg: '', productAttributes: out }
|
||||
}
|
||||
|
||||
function collectCdItemsFromSelectedRows (selectedRows) {
|
||||
const codes = [...new Set(
|
||||
(selectedRows || [])
|
||||
.filter(r => r?.NewItemMode === 'new' && String(r?.NewItemCode || '').trim())
|
||||
.map(r => String(r.NewItemCode).trim().toUpperCase())
|
||||
)]
|
||||
if (!codes.length) return { errMsg: '', cdItems: [] }
|
||||
|
||||
const out = []
|
||||
for (const code of codes) {
|
||||
const draft = store.getCdItemDraft(code)
|
||||
if (!draft) {
|
||||
return { errMsg: `${code} icin cdItem bilgisi eksik`, cdItems: [] }
|
||||
}
|
||||
out.push(normalizeCdItemDraftForPayload(draft))
|
||||
}
|
||||
return { errMsg: '', cdItems: out }
|
||||
}
|
||||
|
||||
function buildMailLineLabelFromRow (row) {
|
||||
const item = String(row?.NewItemCode || row?.OldItemCode || '').trim().toUpperCase()
|
||||
const color1 = String(row?.NewColor || row?.OldColor || '').trim().toUpperCase()
|
||||
@@ -516,14 +927,23 @@ function formatSizes (sizeMap) {
|
||||
function groupItems (items, prevRows = []) {
|
||||
const prevMap = new Map()
|
||||
for (const r of prevRows || []) {
|
||||
if (r?.RowKey) prevMap.set(r.RowKey, String(r.NewDesc || '').trim())
|
||||
if (!r?.RowKey) continue
|
||||
prevMap.set(r.RowKey, {
|
||||
NewDesc: String(r.NewDesc || '').trim(),
|
||||
NewItemCode: String(r.NewItemCode || '').trim().toUpperCase(),
|
||||
NewColor: String(r.NewColor || '').trim().toUpperCase(),
|
||||
NewDim2: String(r.NewDim2 || '').trim().toUpperCase(),
|
||||
NewItemMode: String(r.NewItemMode || '').trim(),
|
||||
NewItemSource: String(r.NewItemSource || '').trim()
|
||||
})
|
||||
}
|
||||
const map = new Map()
|
||||
|
||||
for (const it of items) {
|
||||
const key = buildGroupKey(it)
|
||||
if (!map.has(key)) {
|
||||
const prevDesc = prevMap.get(key) || ''
|
||||
const prev = prevMap.get(key) || {}
|
||||
const prevDesc = prev.NewDesc || ''
|
||||
const fallbackDesc = String((it?.NewDesc || it?.OldDesc) || '').trim()
|
||||
map.set(key, {
|
||||
RowKey: key,
|
||||
@@ -536,10 +956,12 @@ function groupItems (items, prevRows = []) {
|
||||
OrderLineIDs: [],
|
||||
OldSizes: [],
|
||||
OldSizesLabel: '',
|
||||
NewItemCode: '',
|
||||
NewColor: '',
|
||||
NewDim2: '',
|
||||
NewItemCode: prev.NewItemCode || '',
|
||||
NewColor: prev.NewColor || '',
|
||||
NewDim2: prev.NewDim2 || '',
|
||||
NewDesc: prevDesc || fallbackDesc,
|
||||
NewItemMode: prev.NewItemMode || 'empty',
|
||||
NewItemSource: prev.NewItemSource || '',
|
||||
IsVariantMissing: !!it.IsVariantMissing
|
||||
})
|
||||
}
|
||||
@@ -560,6 +982,10 @@ function groupItems (items, prevRows = []) {
|
||||
const sizes = formatSizes(g.__sizeMap || {})
|
||||
g.OldSizes = sizes.list
|
||||
g.OldSizesLabel = sizes.label
|
||||
const info = store.classifyItemCode(g.NewItemCode)
|
||||
g.NewItemCode = info.normalized
|
||||
g.NewItemMode = info.mode
|
||||
if (info.mode === 'empty') g.NewItemSource = ''
|
||||
delete g.__sizeMap
|
||||
out.push(g)
|
||||
}
|
||||
@@ -589,6 +1015,20 @@ async function onBulkSubmit () {
|
||||
$q.notify({ type: 'negative', message: 'Secili satirlarda guncellenecek kayit bulunamadi.' })
|
||||
return
|
||||
}
|
||||
const { errMsg: cdErrMsg, cdItems } = collectCdItemsFromSelectedRows(selectedRows)
|
||||
if (cdErrMsg) {
|
||||
$q.notify({ type: 'negative', message: cdErrMsg })
|
||||
const firstCode = String(cdErrMsg.split(' ')[0] || '').trim()
|
||||
if (firstCode) openCdItemDialog(firstCode)
|
||||
return
|
||||
}
|
||||
const { errMsg: attrErrMsg, productAttributes } = collectProductAttributesFromSelectedRows(selectedRows)
|
||||
if (attrErrMsg) {
|
||||
$q.notify({ type: 'negative', message: attrErrMsg })
|
||||
const firstCode = String(attrErrMsg.split(' ')[0] || '').trim()
|
||||
if (firstCode) openAttributeDialog(firstCode)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const validate = await store.validateUpdates(orderHeaderID.value, lines)
|
||||
@@ -604,7 +1044,7 @@ async function onBulkSubmit () {
|
||||
ok: { label: 'Ekle ve Guncelle', color: 'primary' },
|
||||
cancel: { label: 'Vazgec', flat: true }
|
||||
}).onOk(async () => {
|
||||
await store.applyUpdates(orderHeaderID.value, lines, true)
|
||||
await store.applyUpdates(orderHeaderID.value, lines, true, cdItems, productAttributes)
|
||||
await store.fetchItems(orderHeaderID.value)
|
||||
selectedMap.value = {}
|
||||
await sendUpdateMailAfterApply(selectedRows)
|
||||
@@ -612,7 +1052,7 @@ async function onBulkSubmit () {
|
||||
return
|
||||
}
|
||||
|
||||
await store.applyUpdates(orderHeaderID.value, lines, false)
|
||||
await store.applyUpdates(orderHeaderID.value, lines, false, cdItems, productAttributes)
|
||||
await store.fetchItems(orderHeaderID.value)
|
||||
selectedMap.value = {}
|
||||
await sendUpdateMailAfterApply(selectedRows)
|
||||
@@ -738,6 +1178,16 @@ async function onBulkSubmit () {
|
||||
background: #e3f3ff;
|
||||
}
|
||||
|
||||
.prod-table :deep(.new-item-existing .q-field__control) {
|
||||
background: #eaf9ef !important;
|
||||
border-left: 3px solid #21ba45;
|
||||
}
|
||||
|
||||
.prod-table :deep(.new-item-new .q-field__control) {
|
||||
background: #fff5e9 !important;
|
||||
border-left: 3px solid #f2a100;
|
||||
}
|
||||
|
||||
.prod-table :deep(td.col-desc),
|
||||
.prod-table :deep(th.col-desc),
|
||||
.prod-table :deep(td.col-wrap),
|
||||
|
||||
Reference in New Issue
Block a user