From 47fc7a61788cb9f99e426dec00298d6bbb90caff Mon Sep 17 00:00:00 2001 From: M_Kececi Date: Tue, 14 Apr 2026 16:34:25 +0300 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- svc/main.go | 1 + svc/routes/orders.go | 56 +++++++++++++++++++ ui/src/pages/OrderEntry.vue | 92 ++++++++++++++++++++++++++++++++ ui/src/stores/orderentryStore.js | 73 ++++++++++++++++++++++++- 4 files changed, 221 insertions(+), 1 deletion(-) diff --git a/svc/main.go b/svc/main.go index 4da5052..2528aca 100644 --- a/svc/main.go +++ b/svc/main.go @@ -519,6 +519,7 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router }{ {"/api/order/create", "POST", "insert", routes.CreateOrderHandler(pgDB, mssql)}, {"/api/order/update", "POST", "update", http.HandlerFunc(routes.UpdateOrderHandler)}, + {"/api/order/{id}/bulk-due-date", "POST", "update", routes.BulkUpdateOrderLineDueDateHandler(mssql)}, {"/api/order/get/{id}", "GET", "view", routes.GetOrderByIDHandler(mssql)}, {"/api/orders/list", "GET", "view", routes.OrderListRoute(mssql)}, {"/api/orders/production-list", "GET", "update", routes.OrderProductionListRoute(mssql)}, diff --git a/svc/routes/orders.go b/svc/routes/orders.go index efc3b58..8ab9342 100644 --- a/svc/routes/orders.go +++ b/svc/routes/orders.go @@ -14,6 +14,62 @@ import ( "github.com/gorilla/mux" ) +func BulkUpdateOrderLineDueDateHandler(mssql *sql.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + + claims, ok := auth.GetClaimsFromContext(r.Context()) + if !ok || claims == nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + user := utils.UserFromClaims(claims) + if user == nil { + http.Error(w, "Kullanici dogrulanamadi", http.StatusUnauthorized) + return + } + + orderHeaderID := mux.Vars(r)["id"] + if orderHeaderID == "" { + http.Error(w, "OrderHeaderID bulunamadi", http.StatusBadRequest) + return + } + + var payload struct { + DueDate string `json:"dueDate"` + } + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, "Gecersiz JSON", http.StatusBadRequest) + return + } + + username := user.Username + if username == "" { + username = user.V3Username + } + + updatedLines, headerUpdated, err := queries.BulkUpdateOrderLineDueDate(mssql, orderHeaderID, payload.DueDate, username) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + _ = json.NewEncoder(w).Encode(map[string]any{ + "code": "ORDER_BULK_DUE_DATE_UPDATE_FAILED", + "message": "Siparis satir terminleri guncellenemedi.", + "detail": err.Error(), + }) + return + } + + _ = json.NewEncoder(w).Encode(map[string]any{ + "success": true, + "orderHeaderID": orderHeaderID, + "dueDate": payload.DueDate, + "updatedLines": updatedLines, + "headerUpdated": headerUpdated, + }) + } +} + // ================================ // POST /api/order/update // ================================ diff --git a/ui/src/pages/OrderEntry.vue b/ui/src/pages/OrderEntry.vue index 745a3d2..fda660d 100644 --- a/ui/src/pages/OrderEntry.vue +++ b/ui/src/pages/OrderEntry.vue @@ -262,6 +262,16 @@ @click="openNewRowEditor" :disable="isClosedRow || isViewOnly || !canMutateRows" /> + + + + + + Satir Terminlerini Toplu Guncelle + + + +
+ Tum siparis satiri terminlerini sectiginiz tarihi koyarak guncellemek istediginize emin misiniz? +
+ +
+ + + + + +
+
+ @@ -883,6 +928,8 @@ console.log('🧩 Route parametresi alındı (setup başında):', orderHeaderID. const aktifPB = ref('USD') // Varsayılan para birimi (Cari seçimiyle değişebilir) // 🔹 Model detayları cache (product-detail API verilerini tutar) const productCache = reactive({}) +const showBulkDueDateDialog = ref(false) +const bulkDueDateValue = ref('') const confirmAndSubmit = async () => { if (orderStore.loading) return @@ -918,6 +965,43 @@ const confirmAndSubmit = async () => { } } +function openBulkDueDateDialog() { + if (!canBulkUpdateLineDueDates.value) return + + const firstRowDate = summaryRows.value?.find?.(row => !!row?.terminTarihi)?.terminTarihi || '' + bulkDueDateValue.value = toDateOnly(form.AverageDueDate || firstRowDate || dayjs().format('YYYY-MM-DD')) + showBulkDueDateDialog.value = true +} + +async function confirmBulkDueDateUpdate() { + const dueDate = toDateOnly(bulkDueDateValue.value) + if (!dueDate) { + $q.notify({ + type: 'warning', + message: 'Lutfen bir termin tarihi seciniz.' + }) + return + } + + try { + const result = await orderStore.bulkUpdateOrderLineDueDate(orderHeaderID.value, dueDate) + orderStore.applyBulkLineDueDateLocally(dueDate) + form.AverageDueDate = dueDate + showBulkDueDateDialog.value = false + + $q.notify({ + type: 'positive', + message: `Tum siparis satiri terminleri guncellendi (${Number(result?.updatedLines || 0)} satir).` + }) + } catch (err) { + console.error('❌ confirmBulkDueDateUpdate hata:', err) + $q.notify({ + type: 'negative', + message: err?.message || 'Satir terminleri guncellenemedi.' + }) + } +} + /* =========================================================== 🗓️ SİPARİŞ TARİHLERİ — Varsayılan Değerler @@ -939,6 +1023,14 @@ const canMutateRows = computed(() => { if (isViewOnly.value) return false return isEditMode.value ? canUpdateOrder.value : canWriteOrder.value }) +const canBulkUpdateLineDueDates = computed(() => { + if (!isEditMode.value) return false + if (isViewOnly.value) return false + if (isClosedOrder.value) return false + if (!canUpdateOrder.value) return false + if (!orderHeaderID.value) return false + return Array.isArray(orderStore.summaryRows) && orderStore.summaryRows.length > 0 +}) function notifyNoPermission(message) { $q.notify({ diff --git a/ui/src/stores/orderentryStore.js b/ui/src/stores/orderentryStore.js index f3a0811..84d14a8 100644 --- a/ui/src/stores/orderentryStore.js +++ b/ui/src/stores/orderentryStore.js @@ -668,6 +668,77 @@ export const useOrderEntryStore = defineStore('orderentry', { } , + async bulkUpdateOrderLineDueDate(orderId, dueDate) { + const id = String(orderId || this.header?.OrderHeaderID || '').trim() + const dateText = String(dueDate || '').trim() + if (!id) { + throw new Error('Siparis ID bulunamadi') + } + if (!dateText) { + throw new Error('Termin tarihi secilmedi') + } + + try { + this.loading = true + const res = await api.post(`/order/${encodeURIComponent(id)}/bulk-due-date`, { + dueDate: dateText + }) + return res?.data || {} + } catch (err) { + const detail = await extractApiErrorDetail(err) + const status = err?.status || err?.response?.status || '-' + console.error(`❌ bulkUpdateOrderLineDueDate hata [${status}] order=${id}: ${detail}`) + throw new Error(detail) + } finally { + this.loading = false + } + } + , + + applyBulkLineDueDateLocally(dueDate) { + const dateText = String(dueDate || '').trim() + if (!dateText) return + + const hadUnsavedChanges = this.hasUnsavedChanges + const patchRow = (row) => ({ + ...row, + terminTarihi: dateText, + DueDate: dateText, + DeliveryDate: dateText, + PlannedDateOfLading: dateText + }) + + this.orders = Array.isArray(this.orders) + ? this.orders.map(patchRow) + : [] + + this.summaryRows = Array.isArray(this.summaryRows) + ? this.summaryRows.map(patchRow) + : [] + + this.header = { + ...(this.header || {}), + AverageDueDate: dateText + } + + if (this.originalHeader && typeof this.originalHeader === 'object') { + this.originalHeader = { + ...this.originalHeader, + AverageDueDate: dateText + } + } + + if (Array.isArray(this.originalLines)) { + this.originalLines = this.originalLines.map(patchRow) + } + + this.persistLocalStorage?.() + if (!hadUnsavedChanges) { + this.markAsSaved?.() + } + } + , + async downloadOrderPdf(id = null) { try { const orderId = id || this.header?.OrderHeaderID @@ -3216,6 +3287,7 @@ export const useOrderEntryStore = defineStore('orderentry', { if (!serverOrderId) { throw new Error('OrderHeaderID backend’den dönmedi') } + const mailPayload = this.buildOrderMailPayload(lines, isNew) purgeNewDraftOnExit = isNew /* ======================================================= @@ -3275,7 +3347,6 @@ export const useOrderEntryStore = defineStore('orderentry', { // 📧 Piyasa eşleşen alıcılara sipariş PDF gönderimi (kayıt başarılı olduktan sonra) try { - const mailPayload = this.buildOrderMailPayload(lines, isNew) // UPDATE durumunda da mail gönderimi istendiği için isNew kontrolü kaldırıldı (v3.5) const mailRes = await this.sendOrderToMarketMails(serverOrderId, mailPayload) const sentCount = Number(mailRes?.sentCount || 0)