Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-03-23 10:16:30 +03:00
parent c0053d6058
commit e6e79f8ef4
2 changed files with 152 additions and 10 deletions

View File

@@ -9,11 +9,16 @@ import (
"net/http"
"strings"
"bssapp-backend/auth"
"bssapp-backend/internal/mailer"
)
type sendOrderMarketMailPayload struct {
OrderHeaderID string `json:"orderHeaderID"`
Operation string `json:"operation"`
DeletedItems []string `json:"deletedItems"`
UpdatedItems []string `json:"updatedItems"`
AddedItems []string `json:"addedItems"`
}
func SendOrderMarketMailHandler(pg *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) http.HandlerFunc {
@@ -28,6 +33,11 @@ func SendOrderMarketMailHandler(pg *sql.DB, mssql *sql.DB, ml *mailer.GraphMaile
http.Error(w, "database not initialized", http.StatusInternalServerError)
return
}
claims, ok := auth.GetClaimsFromContext(r.Context())
if !ok || claims == nil {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
var payload sendOrderMarketMailPayload
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
@@ -80,14 +90,52 @@ func SendOrderMarketMailHandler(pg *sql.DB, mssql *sql.DB, ml *mailer.GraphMaile
marketLabel = strings.TrimSpace(marketCode)
}
subject := fmt.Sprintf("Sipariş %s - %s", number, marketLabel)
bodyHTML := fmt.Sprintf(
`<p>Sipariş kaydı oluşturuldu/güncellendi.</p><p><b>Sipariş No:</b> %s<br/><b>Cari:</b> %s<br/><b>Piyasa:</b> %s</p><p>PDF ektedir.</p>`,
htmlEsc(number),
htmlEsc(currAccCode),
htmlEsc(marketLabel),
actor := strings.TrimSpace(claims.Username)
if actor == "" {
actor = strings.TrimSpace(claims.V3Username)
}
if actor == "" {
actor = "Bilinmeyen Kullanici"
}
op := strings.ToLower(strings.TrimSpace(payload.Operation))
isUpdate := op == "update"
subjectAction := "SİPARİŞ KAYDI OLUŞTURULDU"
if isUpdate {
subjectAction = "SİPARİŞ GÜNCELLENDİ."
}
subject := fmt.Sprintf("%s kullanıcısı tarafından %s %s", actor, number, subjectAction)
cariDetail := ""
customerRep := ""
if header != nil {
cariDetail = strings.TrimSpace(header.CurrAccName)
customerRep = strings.TrimSpace(header.CustomerRep)
}
body := make([]string, 0, 12)
body = append(body,
`<p>`,
fmt.Sprintf(`<b>Cari Kodu:</b> %s<br/>`, htmlEsc(currAccCode)),
fmt.Sprintf(`<b>Cari Detay:</b> %s<br/>`, htmlEsc(cariDetail)),
fmt.Sprintf(`<b>Müşteri Temsilcisi:</b> %s<br/>`, htmlEsc(customerRep)),
fmt.Sprintf(`<b>Piyasa:</b> %s`, htmlEsc(marketLabel)),
`</p>`,
)
if isUpdate {
body = append(body,
renderItemListHTML("Silinen Ürün Kodları", payload.DeletedItems),
renderItemListHTML("Güncellenen Ürün Kodları", payload.UpdatedItems),
renderItemListHTML("Eklenen Ürün Kodları", payload.AddedItems),
)
}
body = append(body, `<p><i>Bu sipariş BaggiSS App Uygulamasından oluşturulmuştur.</i></p>`)
body = append(body, `<p>PDF ektedir.</p>`)
bodyHTML := strings.Join(body, "\n")
fileNo := sanitizeFileName(number)
if fileNo == "" {
fileNo = orderID
@@ -256,3 +304,31 @@ func htmlEsc(s string) string {
)
return r.Replace(s)
}
func renderItemListHTML(title string, items []string) string {
clean := make([]string, 0, len(items))
seen := make(map[string]struct{}, len(items))
for _, raw := range items {
v := strings.TrimSpace(raw)
if v == "" {
continue
}
if _, ok := seen[v]; ok {
continue
}
seen[v] = struct{}{}
clean = append(clean, v)
}
if len(clean) == 0 {
return fmt.Sprintf(`<p><b>%s:</b> Yok</p>`, htmlEsc(title))
}
b := make([]string, 0, len(clean)+3)
b = append(b, fmt.Sprintf(`<p><b>%s:</b><br/>`, htmlEsc(title)))
for _, item := range clean {
b = append(b, "- "+htmlEsc(item)+"<br/>")
}
b = append(b, `</p>`)
return strings.Join(b, "\n")
}

View File

@@ -400,7 +400,68 @@ export const useOrderEntryStore = defineStore('orderentry', {
}
,
async sendOrderToMarketMails(orderId) {
buildMailLineLabel(line) {
if (!line || typeof line !== 'object') return ''
const item = String(line.ItemCode || '').trim()
const color1 = String(line.ColorCode || '').trim()
const color2 = String(line.ItemDim2Code || '').trim()
const desc = String(line.LineDescription || '').trim()
if (!item) return ''
const colorPart = color2 ? `${color1}-${color2}` : color1
return [item, colorPart, desc].filter(Boolean).join(' ')
}
,
buildOrderMailPayload(lines = [], isNew = false) {
const uniq = (arr) => [...new Set((arr || []).map(v => String(v || '').trim()).filter(Boolean))]
const normalized = Array.isArray(lines) ? lines : []
const mapLabel = (ln) => this.buildMailLineLabel(ln)
if (isNew) {
return {
operation: 'create',
deletedItems: [],
updatedItems: [],
addedItems: uniq(
normalized
.filter(ln => !ln?._deleteSignal)
.map(mapLabel)
)
}
}
const deletedItems = uniq(
normalized
.filter(ln => ln?._deleteSignal === true)
.map(mapLabel)
)
const updatedItems = uniq(
normalized
.filter(ln => !ln?._deleteSignal && !!ln?.OrderLineID && ln?._dirty === true)
.map(mapLabel)
)
const addedItems = uniq(
normalized
.filter(ln => !ln?._deleteSignal && !ln?.OrderLineID)
.map(mapLabel)
)
return {
operation: 'update',
deletedItems,
updatedItems,
addedItems
}
}
,
async sendOrderToMarketMails(orderId, payload = {}) {
const id = String(orderId || this.header?.OrderHeaderID || '').trim()
if (!id) {
throw new Error('Sipariş ID bulunamadı')
@@ -408,7 +469,11 @@ export const useOrderEntryStore = defineStore('orderentry', {
try {
const res = await api.post('/order/send-market-mail', {
orderHeaderID: id
orderHeaderID: id,
operation: payload?.operation || 'create',
deletedItems: Array.isArray(payload?.deletedItems) ? payload.deletedItems : [],
updatedItems: Array.isArray(payload?.updatedItems) ? payload.updatedItems : [],
addedItems: Array.isArray(payload?.addedItems) ? payload.addedItems : []
})
return res?.data || {}
} catch (err) {
@@ -2867,7 +2932,8 @@ 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 mailRes = await this.sendOrderToMarketMails(serverOrderId)
const mailPayload = this.buildOrderMailPayload(lines, isNew)
const mailRes = await this.sendOrderToMarketMails(serverOrderId, mailPayload)
const sentCount = Number(mailRes?.sentCount || 0)
$q.notify({
type: 'positive',