b2b.systemd
This commit is contained in:
@@ -3,7 +3,10 @@
|
|||||||
🧾 ORDER ENTRY PAGE (BSSApp)
|
🧾 ORDER ENTRY PAGE (BSSApp)
|
||||||
v23 — Sticky-stack + Drawer uyumlu yapı
|
v23 — Sticky-stack + Drawer uyumlu yapı
|
||||||
============================================================ -->
|
============================================================ -->
|
||||||
<q-page class="order-page">
|
<q-page
|
||||||
|
v-if="canReadOrder"
|
||||||
|
class="order-page"
|
||||||
|
>
|
||||||
<!-- 🔄 SAYFA LOADERI -->
|
<!-- 🔄 SAYFA LOADERI -->
|
||||||
<q-inner-loading :showing="loadingHeader || loadingCari || loadingModels" color="primary">
|
<q-inner-loading :showing="loadingHeader || loadingCari || loadingModels" color="primary">
|
||||||
<q-spinner size="50px" />
|
<q-spinner size="50px" />
|
||||||
@@ -210,30 +213,32 @@
|
|||||||
<div class="text-subtitle2 text-weight-bold">Sipariş Formu</div>
|
<div class="text-subtitle2 text-weight-bold">Sipariş Formu</div>
|
||||||
<div>
|
<div>
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="isViewOnly"
|
v-if="isViewOnly && canReadOrder"
|
||||||
label="🖨 SİPARİŞİ YAZDIR"
|
label="🖨 SİPARİŞİ YAZDIR"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="print"
|
icon="print"
|
||||||
class="q-ml-sm"
|
class="q-ml-sm"
|
||||||
@click="orderStore.downloadOrderPdf()"
|
@click="onPrintOrder"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
v-else
|
v-else-if="canSubmitOrder"
|
||||||
:label="isEditMode ? 'TÜMÜNÜ GÜNCELLE' : 'TÜMÜNÜ KAYDET'"
|
:label="isEditMode ? 'TÜMÜNÜ GÜNCELLE' : 'TÜMÜNÜ KAYDET'"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="save"
|
icon="save"
|
||||||
class="q-ml-sm"
|
class="q-ml-sm"
|
||||||
:loading="orderStore.loading"
|
:loading="orderStore.loading"
|
||||||
|
:disable="!canSubmitOrder"
|
||||||
@click="confirmAndSubmit"
|
@click="confirmAndSubmit"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
label="YENİ SİPARİŞ"
|
label="YENİ SİPARİŞ"
|
||||||
|
v-if="canWriteOrder"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
icon="add_circle"
|
icon="add_circle"
|
||||||
class="q-ml-sm"
|
class="q-ml-sm"
|
||||||
@click="resetEditor"
|
@click="onResetEditorClick"
|
||||||
:disable="isClosedRow"
|
:disable="isClosedRow || !canWriteOrder"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -532,12 +537,12 @@
|
|||||||
|
|
||||||
<div class="col-2 q-mt-sm">
|
<div class="col-2 q-mt-sm">
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="selectedSeriSet"
|
v-if="selectedSeriSet && canMutateRows"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="add"
|
icon="add"
|
||||||
label="Seri Ekle"
|
label="Seri Ekle"
|
||||||
@click="applySeriSet"
|
@click="applySeriSet"
|
||||||
:disable="isClosedRow || isViewOnly"
|
:disable="isClosedRow || isViewOnly || !canMutateRows"
|
||||||
:readonly="isViewOnly"
|
:readonly="isViewOnly"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -674,26 +679,28 @@
|
|||||||
<div class="row justify-between items-center q-mt-md">
|
<div class="row justify-between items-center q-mt-md">
|
||||||
<div class="row q-gutter-sm">
|
<div class="row q-gutter-sm">
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canMutateRows"
|
||||||
:color="isEditing ? 'positive' : 'primary'"
|
:color="isEditing ? 'positive' : 'primary'"
|
||||||
:label="isEditing ? 'Güncelle' : 'Kaydet'"
|
:label="isEditing ? 'Güncelle' : 'Kaydet'"
|
||||||
@click="onSaveOrUpdateRow"
|
@click="onSaveOrUpdateRow"
|
||||||
:disable="isClosedRow || isViewOnly"
|
:disable="isClosedRow || isViewOnly || !canMutateRows"
|
||||||
|
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="isEditing"
|
v-if="isEditing && canMutateRows"
|
||||||
color="negative"
|
color="negative"
|
||||||
flat
|
flat
|
||||||
label="Satırı Sil"
|
label="Satırı Sil"
|
||||||
@click="removeSelected"
|
@click="removeSelected"
|
||||||
:disable="isClosedRow || isViewOnly"
|
:disable="isClosedRow || isViewOnly || !canMutateRows"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canMutateRows"
|
||||||
flat
|
flat
|
||||||
color="grey-8"
|
color="grey-8"
|
||||||
label="Formu Temizle"
|
label="Formu Temizle"
|
||||||
@click="resetEditor"
|
@click="onResetEditorClick"
|
||||||
:disable="isClosedRow||isViewOnly"
|
:disable="isClosedRow||isViewOnly || !canMutateRows"
|
||||||
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -734,6 +741,14 @@
|
|||||||
</div> <!-- ✅ order-scroll-y -->
|
</div> <!-- ✅ order-scroll-y -->
|
||||||
|
|
||||||
</q-page>
|
</q-page>
|
||||||
|
<q-page
|
||||||
|
v-else
|
||||||
|
class="order-page flex flex-center"
|
||||||
|
>
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -802,6 +817,15 @@ const productCache = reactive({})
|
|||||||
const confirmAndSubmit = async () => {
|
const confirmAndSubmit = async () => {
|
||||||
if (orderStore.loading) return
|
if (orderStore.loading) return
|
||||||
|
|
||||||
|
if (!hasSubmitPermission()) {
|
||||||
|
notifyNoPermission(
|
||||||
|
isEditMode.value
|
||||||
|
? 'Siparis guncelleme yetkiniz yok'
|
||||||
|
: 'Siparis kaydetme yetkiniz yok'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Grid boşsa
|
// Grid boşsa
|
||||||
if (!orderStore.summaryRows?.length) {
|
if (!orderStore.summaryRows?.length) {
|
||||||
$q.notify({
|
$q.notify({
|
||||||
@@ -838,6 +862,47 @@ const defaultOlusturmaTarihi = today.toISOString().substring(0, 10)
|
|||||||
const defaultTerminTarihi = Termindate.toISOString().substring(0, 10)
|
const defaultTerminTarihi = Termindate.toISOString().substring(0, 10)
|
||||||
|
|
||||||
const isEditMode = computed(() => orderStore.mode === 'edit')
|
const isEditMode = computed(() => orderStore.mode === 'edit')
|
||||||
|
const canSubmitOrder = computed(() => {
|
||||||
|
if (isViewOnly.value) return false
|
||||||
|
return isEditMode.value ? canUpdateOrder.value : canWriteOrder.value
|
||||||
|
})
|
||||||
|
const canMutateRows = computed(() => {
|
||||||
|
if (isViewOnly.value) return false
|
||||||
|
return isEditMode.value ? canUpdateOrder.value : canWriteOrder.value
|
||||||
|
})
|
||||||
|
|
||||||
|
function notifyNoPermission(message) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasSubmitPermission() {
|
||||||
|
if (isViewOnly.value) return false
|
||||||
|
return isEditMode.value ? canUpdateOrder.value : canWriteOrder.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasRowMutationPermission() {
|
||||||
|
if (isViewOnly.value) return false
|
||||||
|
return isEditMode.value ? canUpdateOrder.value : canWriteOrder.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPrintOrder() {
|
||||||
|
if (!canReadOrder.value) {
|
||||||
|
notifyNoPermission('Siparisi goruntuleme yetkiniz yok')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
orderStore.downloadOrderPdf()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onResetEditorClick() {
|
||||||
|
if (!canWriteOrder.value) {
|
||||||
|
notifyNoPermission('Yeni siparis baslatma yetkiniz yok')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await resetEditor()
|
||||||
|
}
|
||||||
|
|
||||||
/* ===========================================================
|
/* ===========================================================
|
||||||
🔹 FORM NESNESİ — TEMEL ALANLAR
|
🔹 FORM NESNESİ — TEMEL ALANLAR
|
||||||
@@ -1929,6 +1994,15 @@ function scrollToRow(clientKey) {
|
|||||||
🔹 SERİ SETİ UYGULAMA (FINAL — grpKey SAFE)
|
🔹 SERİ SETİ UYGULAMA (FINAL — grpKey SAFE)
|
||||||
=========================================================== */
|
=========================================================== */
|
||||||
function applySeriSet() {
|
function applySeriSet() {
|
||||||
|
if (!hasRowMutationPermission()) {
|
||||||
|
notifyNoPermission(
|
||||||
|
isEditMode.value
|
||||||
|
? 'Siparis satiri guncelleme yetkiniz yok'
|
||||||
|
: 'Siparis satiri ekleme yetkiniz yok'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!selectedSeriSet.value) return
|
if (!selectedSeriSet.value) return
|
||||||
|
|
||||||
/* 🔑 TEK KAYNAK */
|
/* 🔑 TEK KAYNAK */
|
||||||
@@ -1984,6 +2058,11 @@ function updateTotals(f) {
|
|||||||
|
|
||||||
|
|
||||||
function removeSelected() {
|
function removeSelected() {
|
||||||
|
if (!hasRowMutationPermission()) {
|
||||||
|
notifyNoPermission('Siparis satiri silme/guncelleme yetkiniz yok')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const row = selectedRow.value
|
const row = selectedRow.value
|
||||||
if (!row) {
|
if (!row) {
|
||||||
$q.notify({ type: 'warning', message: 'Silmek için önce bir satır seçmelisiniz.' })
|
$q.notify({ type: 'warning', message: 'Silmek için önce bir satır seçmelisiniz.' })
|
||||||
@@ -2666,6 +2745,15 @@ async function onColor2Change(colorCode2) {
|
|||||||
const bedenStock = ref([]) // Görsel tablo için stok listesi
|
const bedenStock = ref([]) // Görsel tablo için stok listesi
|
||||||
const stockMap = ref({}) // { "48": 12, "50": 7, ... } şeklinde key-value map
|
const stockMap = ref({}) // { "48": 12, "50": 7, ... } şeklinde key-value map
|
||||||
const onSaveOrUpdateRow = async () => {
|
const onSaveOrUpdateRow = async () => {
|
||||||
|
if (!hasRowMutationPermission()) {
|
||||||
|
notifyNoPermission(
|
||||||
|
isEditMode.value
|
||||||
|
? 'Siparis satiri guncelleme yetkiniz yok'
|
||||||
|
: 'Siparis satiri kaydetme yetkiniz yok'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
await orderStore.saveOrUpdateRowUnified({
|
await orderStore.saveOrUpdateRowUnified({
|
||||||
form,
|
form,
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<!-- 🟡 TASLAK -->
|
<!-- 🟡 TASLAK -->
|
||||||
<div
|
<div
|
||||||
v-if="hasDraft && canUpdateOrder"
|
v-if="hasDraft && canWriteOrder"
|
||||||
class="draft-card q-pa-lg rounded-borders shadow-2 bg-white"
|
class="draft-card q-pa-lg rounded-borders shadow-2 bg-white"
|
||||||
>
|
>
|
||||||
<div class="text-subtitle1 text-bold text-negative">
|
<div class="text-subtitle1 text-bold text-negative">
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
color="primary"
|
color="primary"
|
||||||
icon="login"
|
icon="login"
|
||||||
label="TASLAĞA DEVAM ET"
|
label="TASLAĞA DEVAM ET"
|
||||||
:disable="!canUpdateOrder"
|
:disable="!canWriteOrder"
|
||||||
@click="continueDraft"
|
@click="continueDraft"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -80,11 +80,10 @@ import { useQuasar } from 'quasar'
|
|||||||
import { useOrderEntryStore } from 'src/stores/orderentryStore'
|
import { useOrderEntryStore } from 'src/stores/orderentryStore'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canWrite } = usePermission()
|
||||||
|
|
||||||
const canReadOrder = canRead('order')
|
const canReadOrder = canRead('order')
|
||||||
const canWriteOrder = canWrite('order')
|
const canWriteOrder = canWrite('order')
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
@@ -130,7 +129,7 @@ const draftNumber = computed(() => {
|
|||||||
|
|
||||||
function continueDraft () {
|
function continueDraft () {
|
||||||
|
|
||||||
if (!canUpdateOrder.value) {
|
if (!canWriteOrder.value) {
|
||||||
$q.notify({
|
$q.notify({
|
||||||
type: 'negative',
|
type: 'negative',
|
||||||
message: 'Taslak güncelleme yetkiniz yok'
|
message: 'Taslak güncelleme yetkiniz yok'
|
||||||
|
|||||||
@@ -2,6 +2,25 @@ import { defineStore } from 'pinia'
|
|||||||
import api from 'src/services/api'
|
import api from 'src/services/api'
|
||||||
import { useAuthStore } from 'stores/authStore'
|
import { useAuthStore } from 'stores/authStore'
|
||||||
|
|
||||||
|
const ACTION_ALIASES = {
|
||||||
|
read: ['read', 'view'],
|
||||||
|
view: ['read', 'view'],
|
||||||
|
write: ['write', 'insert'],
|
||||||
|
insert: ['write', 'insert'],
|
||||||
|
update: ['update'],
|
||||||
|
delete: ['delete'],
|
||||||
|
export: ['export']
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeToken (value) {
|
||||||
|
return String(value || '').trim().toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function actionCandidates (action) {
|
||||||
|
const key = normalizeToken(action)
|
||||||
|
return ACTION_ALIASES[key] || [key]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const usePermissionStore = defineStore('permission', {
|
export const usePermissionStore = defineStore('permission', {
|
||||||
|
|
||||||
@@ -44,11 +63,13 @@ export const usePermissionStore = defineStore('permission', {
|
|||||||
|
|
||||||
if (apiPathOrPerm.includes(':')) {
|
if (apiPathOrPerm.includes(':')) {
|
||||||
|
|
||||||
const [module, action] = apiPathOrPerm.split(':')
|
const [moduleRaw, actionRaw] = apiPathOrPerm.split(':')
|
||||||
|
const module = normalizeToken(moduleRaw)
|
||||||
|
const actions = actionCandidates(actionRaw)
|
||||||
|
|
||||||
return state.matrix.some(p =>
|
return state.matrix.some(p =>
|
||||||
p.module === module &&
|
normalizeToken(p.module) === module &&
|
||||||
p.action === action &&
|
actions.includes(normalizeToken(p.action)) &&
|
||||||
p.allowed === true
|
p.allowed === true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -94,12 +115,13 @@ export const usePermissionStore = defineStore('permission', {
|
|||||||
hasModule: (state) => (module) => {
|
hasModule: (state) => (module) => {
|
||||||
|
|
||||||
const auth = useAuthStore()
|
const auth = useAuthStore()
|
||||||
|
const moduleKey = normalizeToken(module)
|
||||||
|
|
||||||
if (auth.isAdmin) return true
|
if (auth.isAdmin) return true
|
||||||
if (!state.loaded) return false
|
if (!state.loaded) return false
|
||||||
|
|
||||||
return state.matrix.some(p =>
|
return state.matrix.some(p =>
|
||||||
p.module === module &&
|
normalizeToken(p.module) === moduleKey &&
|
||||||
p.allowed === true
|
p.allowed === true
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -110,13 +132,15 @@ export const usePermissionStore = defineStore('permission', {
|
|||||||
hasPermission: (state) => (module, action) => {
|
hasPermission: (state) => (module, action) => {
|
||||||
|
|
||||||
const auth = useAuthStore()
|
const auth = useAuthStore()
|
||||||
|
const moduleKey = normalizeToken(module)
|
||||||
|
const actions = actionCandidates(action)
|
||||||
|
|
||||||
if (auth.isAdmin) return true
|
if (auth.isAdmin) return true
|
||||||
if (!state.loaded) return false
|
if (!state.loaded) return false
|
||||||
|
|
||||||
return state.matrix.some(p =>
|
return state.matrix.some(p =>
|
||||||
p.module === module &&
|
normalizeToken(p.module) === moduleKey &&
|
||||||
p.action === action &&
|
actions.includes(normalizeToken(p.action)) &&
|
||||||
p.allowed === true
|
p.allowed === true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user