Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -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)},
|
||||
|
||||
@@ -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
|
||||
// ================================
|
||||
|
||||
@@ -262,6 +262,16 @@
|
||||
@click="openNewRowEditor"
|
||||
:disable="isClosedRow || isViewOnly || !canMutateRows"
|
||||
/>
|
||||
<q-btn
|
||||
v-if="isEditMode && canBulkUpdateLineDueDates"
|
||||
label="SATIR TERMINLERINI TOPLU GUNCELLE"
|
||||
color="warning"
|
||||
icon="event"
|
||||
class="q-ml-sm"
|
||||
:loading="orderStore.loading"
|
||||
:disable="orderStore.loading || !canBulkUpdateLineDueDates"
|
||||
@click="openBulkDueDateDialog"
|
||||
/>
|
||||
<q-btn
|
||||
v-if="canSubmitOrder"
|
||||
:label="isEditMode ? 'TÜMÜNÜ GÜNCELLE' : 'TÜMÜNÜ KAYDET'"
|
||||
@@ -450,6 +460,41 @@
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<!-- =======================================================
|
||||
🔹 TOPLU TERMIN GUNCELLEME
|
||||
======================================================== -->
|
||||
<q-dialog v-model="showBulkDueDateDialog" persistent>
|
||||
<q-card style="min-width: 420px; max-width: 90vw;">
|
||||
<q-card-section class="text-subtitle1 text-weight-bold">
|
||||
Satir Terminlerini Toplu Guncelle
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="q-pt-none">
|
||||
<div class="q-mb-md">
|
||||
Tum siparis satiri terminlerini sectiginiz tarihi koyarak guncellemek istediginize emin misiniz?
|
||||
</div>
|
||||
<q-input
|
||||
v-model="bulkDueDateValue"
|
||||
type="date"
|
||||
label="Yeni Termin Tarihi"
|
||||
filled
|
||||
dense
|
||||
autofocus
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat label="Iptal" v-close-popup />
|
||||
<q-btn
|
||||
color="primary"
|
||||
label="Evet"
|
||||
:loading="orderStore.loading"
|
||||
@click="confirmBulkDueDateUpdate"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<!-- =======================================================
|
||||
🔹 SATIR DÜZENLEYİCİ FORM (EDITOR)
|
||||
======================================================== -->
|
||||
@@ -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({
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user