Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-03-06 12:13:30 +03:00
parent ffa8b30b81
commit 46f4d15ac7
5 changed files with 138 additions and 119 deletions

View File

@@ -10,22 +10,8 @@ import (
) )
// DETAIL (ALT TABLO) // DETAIL (ALT TABLO)
func GetStatementDetails(ctx context.Context, accountCode, startDate, endDate string, parislemler []string) ([]models.StatementDetail, error) { func GetStatementDetails(ctx context.Context, belgeNo string) ([]models.StatementDetail, error) {
inParislem := "" query := `
if len(parislemler) > 0 {
pp := make([]string, len(parislemler))
for i, v := range parislemler {
pp[i] = strings.TrimSpace(v)
}
inParislem = strings.Join(pp, ",")
}
piyasaScope, err := buildPiyasaExistsForCariCode(ctx, "a.CurrAccCode")
if err != nil {
return nil, err
}
query := fmt.Sprintf(`
SELECT SELECT
CONVERT(varchar(10), a.InvoiceDate, 23) AS Belge_Tarihi, CONVERT(varchar(10), a.InvoiceDate, 23) AS Belge_Tarihi,
a.InvoiceNumber AS Belge_Ref_Numarasi, a.InvoiceNumber AS Belge_Ref_Numarasi,
@@ -37,7 +23,7 @@ SELECT
a.ItemCode AS Urun_Kodu, a.ItemCode AS Urun_Kodu,
a.ColorCode AS Urun_Rengi, a.ColorCode AS Urun_Rengi,
SUM(a.Qty1) AS Toplam_Adet, SUM(a.Qty1) AS Toplam_Adet,
CAST(SUM(a.Qty1 * ABS(a.Doc_Price)) / NULLIF(SUM(a.Qty1),0) AS numeric(18,4)) AS Doviz_Fiyat, SUM(ABS(a.Doc_Price)) AS Toplam_Fiyat,
CAST(SUM(a.Qty1 * ABS(a.Doc_Price)) AS numeric(18,2)) AS Toplam_Tutar CAST(SUM(a.Qty1 * ABS(a.Doc_Price)) AS numeric(18,2)) AS Toplam_Tutar
FROM AllInvoicesWithAttributes a FROM AllInvoicesWithAttributes a
LEFT JOIN prItemAttribute AnaGrup LEFT JOIN prItemAttribute AnaGrup
@@ -46,54 +32,40 @@ LEFT JOIN cdItemAttributeDesc AnaGrupDesc
ON AnaGrup.AttributeTypeCode = AnaGrupDesc.AttributeTypeCode ON AnaGrup.AttributeTypeCode = AnaGrupDesc.AttributeTypeCode
AND AnaGrup.AttributeCode = AnaGrupDesc.AttributeCode AND AnaGrup.AttributeCode = AnaGrupDesc.AttributeCode
AND AnaGrup.ItemTypeCode = AnaGrupDesc.ItemTypeCode AND AnaGrup.ItemTypeCode = AnaGrupDesc.ItemTypeCode
LEFT JOIN prItemAttribute AltGrup LEFT JOIN prItemAttribute AltGrup
ON a.ItemCode = AltGrup.ItemCode AND AltGrup.AttributeTypeCode = 2 ON a.ItemCode = AltGrup.ItemCode AND AltGrup.AttributeTypeCode = 2
LEFT JOIN cdItemAttributeDesc AltGrupDesc LEFT JOIN cdItemAttributeDesc AltGrupDesc
ON AltGrup.AttributeTypeCode = AltGrupDesc.AttributeTypeCode ON AltGrup.AttributeTypeCode = AltGrupDesc.AttributeTypeCode
AND AltGrup.AttributeCode = AltGrupDesc.AttributeCode AND AltGrup.AttributeCode = AltGrupDesc.AttributeCode
AND AltGrup.ItemTypeCode = AltGrupDesc.ItemTypeCode AND AltGrup.ItemTypeCode = AltGrupDesc.ItemTypeCode
LEFT JOIN prItemAttribute Garson LEFT JOIN prItemAttribute Garson
ON a.ItemCode = Garson.ItemCode AND Garson.AttributeTypeCode = 44 ON a.ItemCode = Garson.ItemCode AND Garson.AttributeTypeCode = 44
LEFT JOIN cdItemAttributeDesc GarsonDesc LEFT JOIN cdItemAttributeDesc GarsonDesc
ON Garson.AttributeTypeCode = GarsonDesc.AttributeTypeCode ON Garson.AttributeTypeCode = GarsonDesc.AttributeTypeCode
AND Garson.AttributeCode = GarsonDesc.AttributeCode AND Garson.AttributeCode = GarsonDesc.AttributeCode
AND Garson.ItemTypeCode = GarsonDesc.ItemTypeCode AND Garson.ItemTypeCode = GarsonDesc.ItemTypeCode
LEFT JOIN prItemAttribute FitTbl LEFT JOIN prItemAttribute FitTbl
ON a.ItemCode = FitTbl.ItemCode AND FitTbl.AttributeTypeCode = 38 ON a.ItemCode = FitTbl.ItemCode AND FitTbl.AttributeTypeCode = 38
LEFT JOIN cdItemAttributeDesc FitDesc LEFT JOIN cdItemAttributeDesc FitDesc
ON FitTbl.AttributeTypeCode = FitDesc.AttributeTypeCode ON FitTbl.AttributeTypeCode = FitDesc.AttributeTypeCode
AND FitTbl.AttributeCode = FitDesc.AttributeCode AND FitTbl.AttributeCode = FitDesc.AttributeCode
AND FitTbl.ItemTypeCode = FitDesc.ItemTypeCode AND FitTbl.ItemTypeCode = FitDesc.ItemTypeCode
LEFT JOIN prItemAttribute KisaKar LEFT JOIN prItemAttribute KisaKar
ON a.ItemCode = KisaKar.ItemCode AND KisaKar.AttributeTypeCode = 41 ON a.ItemCode = KisaKar.ItemCode AND KisaKar.AttributeTypeCode = 41
LEFT JOIN cdItemAttributeDesc KisaKarDesc LEFT JOIN cdItemAttributeDesc KisaKarDesc
ON KisaKar.AttributeTypeCode = KisaKarDesc.AttributeTypeCode ON KisaKar.AttributeTypeCode = KisaKarDesc.AttributeTypeCode
AND KisaKar.AttributeCode = KisaKarDesc.AttributeCode AND KisaKar.AttributeCode = KisaKarDesc.AttributeCode
AND KisaKar.ItemTypeCode = KisaKarDesc.ItemTypeCode AND KisaKar.ItemTypeCode = KisaKarDesc.ItemTypeCode
WHERE REPLACE(a.CurrAccCode, ' ', '') LIKE REPLACE(@Carikod, ' ', '') + '%%' WHERE LTRIM(RTRIM(a.InvoiceNumber)) = LTRIM(RTRIM(@BelgeNo))
AND a.InvoiceDate BETWEEN @StartDate AND @EndDate
AND %s
%s
GROUP BY a.InvoiceDate, a.InvoiceNumber, a.ItemCode, a.ColorCode GROUP BY a.InvoiceDate, a.InvoiceNumber, a.ItemCode, a.ColorCode
ORDER BY Belge_Tarihi, Belge_Ref_Numarasi, Urun_Kodu;`, ORDER BY Belge_Tarihi, Belge_Ref_Numarasi, Urun_Kodu;`
piyasaScope,
func() string {
if inParislem == "" {
return ""
}
return fmt.Sprintf(`AND EXISTS (
SELECT 1
FROM CurrAccBookATAttributesFilter f
WHERE f.CurrAccBookID = a.CurrAccBookID
AND f.ATAtt01 IN (%s)
)`, inParislem)
}(),
)
rows, err := db.MssqlDB.QueryContext(ctx, query, rows, err := db.MssqlDB.QueryContext(ctx, query,
sql.Named("Carikod", normalizeMasterAccountCode(accountCode)), sql.Named("BelgeNo", strings.TrimSpace(belgeNo)),
sql.Named("StartDate", startDate),
sql.Named("EndDate", endDate),
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("detay sorgu hatasi: %v", err) return nil, fmt.Errorf("detay sorgu hatasi: %v", err)

View File

@@ -18,21 +18,15 @@ func GetStatementDetailsHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
vars := mux.Vars(r) _ = mux.Vars(r)
accountCode := vars["accountCode"]
if accountCode == "" { belgeNo := r.URL.Query().Get("belgeno")
accountCode = vars["id"] if belgeNo == "" {
} http.Error(w, "belgeno is required", http.StatusBadRequest)
if accountCode == "" {
http.Error(w, "account code is required", http.StatusBadRequest)
return return
} }
startDate := r.URL.Query().Get("startdate") details, err := queries.GetStatementDetails(r.Context(), belgeNo)
endDate := r.URL.Query().Get("enddate")
parislemler := r.URL.Query()["parislemler"]
details, err := queries.GetStatementDetails(r.Context(), accountCode, startDate, endDate, parislemler)
if err != nil { if err != nil {
http.Error(w, "Error fetching statement details: "+err.Error(), http.StatusInternalServerError) http.Error(w, "Error fetching statement details: "+err.Error(), http.StatusInternalServerError)
return return

View File

@@ -240,13 +240,13 @@
<!-- Detay tablosu --> <!-- Detay tablosu -->
<q-tr <q-tr
v-if="props.row._type === 'data' && expandedRows[props.row.belge_no]" v-if="props.row._type === 'data' && expandedRows[getRowExpandKey(props.row)]"
class="sub-row" class="sub-row"
> >
<q-td colspan="100%"> <q-td colspan="100%">
<q-table <q-table
:rows="detailStore.getDetailsByBelge(props.row.belge_no)" :rows="detailStore.getDetailsByRowKey(getRowExpandKey(props.row))"
:columns="detailColumns(props.row.belge_no)" :columns="detailColumns(getRowExpandKey(props.row))"
row-key="Urun_Kodu" row-key="Urun_Kodu"
flat flat
dense dense
@@ -387,8 +387,8 @@ function buildColumns(data) {
const columns = computed(() => buildColumns(statementheaderStore.headers)) const columns = computed(() => buildColumns(statementheaderStore.headers))
function detailColumns(belgeNo) { function detailColumns(rowOrBelgeNo) {
const details = detailStore.getDetailsByBelge(belgeNo) const details = detailStore.getDetailsByRowKey(rowOrBelgeNo)
return buildColumns(details) return buildColumns(details)
} }
@@ -417,33 +417,57 @@ async function onFilterClick() {
excludeopening: excludeOpening.value excludeopening: excludeOpening.value
}) })
await detailStore.loadDetails({
accountCode: selectedCari.value,
startDate: dateFrom.value,
endDate: dateTo.value,
parislemler: selectedMonType.value
})
} }
/* Grup satırları için özel rowKey */ /* Grup satırları için özel rowKey */
const rowKeyFn = (row) => const rowKeyFn = (row) =>
row._type === 'group' ? `grp-${row.para_birimi}` : row.belge_no row._type === 'group' ? `grp-${row.para_birimi}` : getRowExpandKey(row)
function getRowExpandKey (row) {
return [
String(row?.belge_no || '').trim(),
String(row?.belge_tarihi || '').trim(),
String(row?.para_birimi || '').trim(),
String(row?.islem_tipi || '').trim(),
String(row?.cari_kod || '').trim()
].join('|')
}
/* Detay açma sadece expand kontrolü */ /* Detay açma sadece expand kontrolü */
function toggleRowDetails(row) { async function toggleRowDetails(row) {
if (row._type === 'group') return if (row._type === 'group') return
expandedRows.value[row.belge_no] = !expandedRows.value[row.belge_no] const key = getRowExpandKey(row)
const next = !expandedRows.value[key]
expandedRows.value[key] = next
if (!next) return
if (!row?.belge_no || String(row.belge_no).trim() === 'Baslangic_devir') return
if (detailStore.hasDetailsByRowKey(key)) return
await detailStore.loadDetails({
accountCode: selectedCari.value,
belgeNo: row.belge_no,
rowKey: key
})
} }
/* Tüm detayları aç/kapat */ /* Tüm detayları aç/kapat */
function toggleAllDetails() { async function toggleAllDetails() {
allDetailsOpen.value = !allDetailsOpen.value allDetailsOpen.value = !allDetailsOpen.value
if (allDetailsOpen.value) { if (allDetailsOpen.value) {
const dataRows = []
for (const row of statementheaderStore.headers) { for (const row of statementheaderStore.headers) {
if (row.belge_no) { if (row.belge_no) {
expandedRows.value[row.belge_no] = true const key = getRowExpandKey(row)
expandedRows.value[key] = true
dataRows.push(row)
} }
} }
await detailStore.preloadForRows({
accountCode: selectedCari.value,
rows: dataRows,
getRowKey: getRowExpandKey
})
} else { } else {
expandedRows.value = {} expandedRows.value = {}
} }

View File

@@ -4,15 +4,16 @@ import api from 'src/services/api'
export const useStatementdetailStore = defineStore('statementdetail', { export const useStatementdetailStore = defineStore('statementdetail', {
state: () => ({ state: () => ({
details: [], detailsByRow: {},
detailsByBelge: {},
loading: false, loading: false,
error: null error: null
}), }),
actions: { actions: {
async loadDetails ({ accountCode, startDate, endDate, parislemler }) { async loadDetails ({ accountCode, belgeNo, rowKey }) {
if (!accountCode) { if (!accountCode) {
this.error = 'Geçerli bir cari kod seçilmedi.' this.error = 'Gecerli bir cari kod secilmedi.'
return return
} }
@@ -20,46 +21,74 @@ export const useStatementdetailStore = defineStore('statementdetail', {
this.error = null this.error = null
try { try {
// ✅ Params (arrayFormat=repeat global) const normalizedBelgeNo = String(belgeNo || '').trim()
const params = { const params = { belgeno: normalizedBelgeNo }
startdate: startDate,
enddate: endDate if (this.detailsByBelge[normalizedBelgeNo]) {
const keyCached = String(rowKey || '').trim()
if (keyCached) {
this.detailsByRow[keyCached] = this.detailsByBelge[normalizedBelgeNo]
}
return
} }
if (Array.isArray(parislemler) && parislemler.length > 0) {
params.parislemler = parislemler.filter(
p => p !== undefined && p !== null && p !== ''
)
}
// 🔐 TOKEN + SERIALIZER + ERROR HANDLING OTOMATİK
const res = await api.get( const res = await api.get(
`/statements/${accountCode}/details`, `/statements/${encodeURIComponent(accountCode)}/details`,
{ params } { params }
) )
this.details = res.data || [] const key = String(rowKey || '').trim()
const rows = Array.isArray(res.data) ? res.data : []
if (normalizedBelgeNo) {
this.detailsByBelge[normalizedBelgeNo] = rows
}
if (key) {
this.detailsByRow[key] = rows
}
} catch (err) { } catch (err) {
console.error('Details yüklenemedi:', err) console.error('Details yuklenemedi:', err)
this.error = this.error =
err?.data?.message || err?.data?.message ||
err?.message || err?.message ||
'Detaylar yüklenemedi' 'Detaylar yuklenemedi'
} finally { } finally {
this.loading = false this.loading = false
} }
}, },
getDetailsByBelge (belgeNo) { hasDetailsByRowKey (rowKey) {
const needle = String(belgeNo || '').trim() const key = String(rowKey || '').trim()
return this.details.filter( return Array.isArray(this.detailsByRow[key])
d => String(d.belge_ref_numarasi || '').trim() === needle },
getDetailsByRowKey (rowKey) {
const key = String(rowKey || '').trim()
return this.detailsByRow[key] || []
},
async preloadForRows ({ accountCode, rows, getRowKey }) {
const tasks = []
for (const row of rows || []) {
const belgeNo = String(row?.belge_no || '').trim()
if (!belgeNo || belgeNo === 'Baslangic_devir') continue
const rowKey = String(getRowKey(row) || '').trim()
if (!rowKey) continue
if (this.hasDetailsByRowKey(rowKey)) continue
tasks.push(
this.loadDetails({ accountCode, belgeNo, rowKey })
) )
}
if (tasks.length === 0) return
await Promise.all(tasks)
}, },
reset () { reset () {
this.details = [] this.detailsByRow = {}
this.detailsByBelge = {}
this.loading = false this.loading = false
this.error = null this.error = null
} }